9

I like the shortcut in C# of lock(myLock){ /* do stuff */}. Is there an equivalent for read/write locks? (Specifically ReaderWriterLockSlim.) Right now, I use the following custom method, which I think works, but is kind of annoying because I have to pass in my action as an anonymous function, and I would prefer to use a standard locking mechanism if possible.

    void bool DoWithWriteLock(ReaderWriterLockSlim RWLock, int TimeOut, Action Fn)
    {
        bool holdingLock = false;
        try
        {
            if (RWLock.TryEnterWriteLock(TimeOut))
            {
                holdingLock = true;
                Fn();
            }
        }
        finally
        {
            if (holdingLock)
            {
                RWLock.ExitWriteLock();
            }
        }
        return holdingLock;
    }
Xodarap
  • 11,581
  • 11
  • 56
  • 94
  • 1
    The *try* statement is in the wrong place. Put it *after* TryEnterWriteLock(). No more need for a variable, a shortcut gets to be pointless. – Hans Passant Dec 06 '10 at 18:30

1 Answers1

14

You can't override the behaviour of the lock keyword. A common technique is to hijack the using keyword.

  1. Make DoWithWriteLock return an IDisposable
  2. Keep the TryEnterWriteLock call inside the DoWithWriteLock method
  3. Return an object that implements IDisposable. In that object's Dispose method, put the call to ExitWriteLock.

The end result:

// Before
DoWithWriteLock(rwLock,
    delegate
    {
        Do1();
        Do2()
    } );

// After
using (DoWithWriteLock(rwLock))
{
    Do1();
    Do2();
}
Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
Tim Robinson
  • 53,480
  • 10
  • 121
  • 138
  • 1
    before can be much better: `DoWithWriteLock(rwLock, () => { Do1(); Do2() } );` – Andrey Dec 06 '10 at 18:20
  • Hi Tim. Is it true this would be easier in F#? – jonnii Dec 06 '10 at 18:20
  • Is there an analogous way to do this for TryEnterWriteLock with a timeout? – Xodarap Dec 06 '10 at 18:55
  • @jonnii F#'s `lock` function is essentially the OP's original `DoWithWriteLock`, but using `Monitor.Enter`: `lock syncRoot (fun () -> do1 |> do2)` – Tim Robinson Dec 06 '10 at 19:10
  • @Xodarap If you can work out a way to smuggle the result of `TryEnterWriteLock` out of the method at the same time as returning `IDisposable`. Maybe: `bool acquired; using (TryDoWithWriteLock(rwLock, out acquired)) {...}` – Tim Robinson Dec 06 '10 at 19:11
  • 2
    In the actual implementation, it's best to return a struct that publicly implements IDisposable (to avoid unnecessary heap allocations and/or boxing); see http://blogs.msdn.com/b/ericgu/archive/2004/03/24/95743.aspx for background. – Bradley Grainger Jan 05 '11 at 13:16