If you want to make a thread safe wrapper for a non-thread safe object then it's generally a bad idea to expose the non-thread safe object from the wrapper. Once you've exposed them it's very difficult to ensure that consumers use them in a thread safe way which defeats the purpose of the wrapper class. Instead of exposing the raw
File
object(s), add thread safe methods to the
ThreadSafeFileInstance
class that perform the thread safe operations for consumer classes. Example: you'd like to wrap a
File
in
ThreadSafeFileInstance
so you start with this:
internal sealed class ThreadSafeFileInstance
{
private readonly object _fileLock = new object();
private FileStream _file;
}
If you expose the
FileStream
through a property then you also have to expose the lock object so that consumers can synchronize on it, but there's no way to guarantee that they actually do it. An alternative way would be to provide separate
GetHandle
,
ReleaseHandle
methods, but again it's difficult to enforce proper usage of those methods. What if a class calls
GetHandle
and then forgets to call
ReleaseHandle
?
Instead, provide methods that do thread safe operations:
internal sealed class ThreadSafeFileInstance
{
private readonly object _fileLock = new object();
private FileStream _file;
internal void Append(string data)
{
lock (_fileLock)
{
_file.Write(Encoding.ASCII.GetBytes(data), 0, data.Length);
}
}
}
Also like Arun Jacob said, use a
lock
(which internally uses
Monitor
s) instead of using
Mutex
es unless you absolutely need to use
Mutex
es. For protecting single resource inside of a single application a
Mutex
is overkill.