Search code examples
c#using-statementreaderwriterlockslim

using (IDisposable) vs. class field - correct usage of ReaderWriterLockSlim


In a FileWriter class that will be used by different threads, I currently use a ReaderWriterLockSlim to prevent errors occurring when two threads try to write to the file at the same time like this:

(1)

public class FileWriter
{
    private ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim();

    public void WriteToFile(string message)
    {
        try
        {
            this.readerWriterLock.EnterWriteLock();    
            // the writing happens here
        }
        finally
        {
            this.readerWriterLockSlim.ExitWriteLock();
        }
    }
}

which does work. But after that, I read that ReaderWriterLockSlim implements IDisposable, and so I wondered whether

(2)

public class FileWriter
{
    public void WriteToFile(string message)
    {
        using (ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim())
        {
            readerWriterLockSlim.EnterWriteLock();
            // the writing happens here
            readerWriterLockSlim.ExitWriteLock();
        }
    }
}

would be the "better" approach and whether it might introduce some new drawbacks. My gut feeling tells me that I probably shouldn't create a new ReaderWriterLockSlim every time the method is called but rather only once as in (2).

Sadly though, it does not work (it's as if I hadn't even used a lock) and so I figured that (2) can't be correct. But then again, why would ReaderWriterLockSlim implement IDisposable if it wasn't planned to be used as in (2)?


What is the correct usage of ReaderWriterLockSlim?


Solution

  • Not every IDisposable is directly used in a using statement. The other pattern is if you have an IDisposable in one of your classes fields (and your class "owns" that object1), then your class should also implement IDisposable and clean up its disposables during Dispose.

    You're correct that your re-write is wrong, since every caller is using a different lock object and so no exclusion is happening.

    See Dispose Pattern:

    DO implement the Basic Dispose Pattern on types containing instances of disposable types. See the Basic Dispose Pattern section for details on the basic pattern.


    1Thanks to Dirk's comment for the important caveat. If you're in a situation where you're not trying to control an object's lifetime, it's not appropriate to Dispose of such objects