4
\$\begingroup\$

In current project I'm using a lot ReaderWriterLockSlim for synchronizing reading and writing values. Handling try { EnterReadLock(); .... } finaly { ExitReadLock(); } every time I need access value seems to me as copying code. So I created extension methods for ReaderWriterLockSlim which makes me coding much easer and faster (and reusable i think).

However I would like know, if you found some disadvantages in the extension methods I missed or forgot. There are three extension methods:

  • ReadOnly<T>(this ReaderWriterLockSlim self, Func<T> readFunc) // calls EnterReadLock()
  • Read<T>(this ReaderWriterLockSlim self, Func<T> readFunc) // calls EnterUpgradeableReadLock()
  • Write(this ReaderWriterLockSlim self, Action writeAction) // calls EnterWriteLock()
  • Write<T>(this ReaderWriterLockSlim self, Func<T> writeAction) // calls EnterWriteLock()

There is code of ReadOnly<T>(...) method. All methods looks similar.

public static T ReadOnly<T>(this ReaderWriterLockSlim self, Func<T> readFunc) {
    if (object.ReferenceEquals(self, null)) { throw new ArgumentNullException("self"); }
    if (object.ReferenceEquals(readFunc, null)) { throw new ArgumentNullException("readFunc"); }

    T result;

    // flag, if lock was entered
    bool lockEntered = false;
    try {
        // I don't want the ThreadAbortException during claiming the lock
        Thread.BeginCriticalRegion();
        try {
            self.EnterReadLock();
            lockEntered = true;
        }
        finally {
            Thread.EndCriticalRegion();
        }

        result = readFunc();
    }
    finally {
        // I don't want the ThreadAbortException during releasing the lock
        Thread.BeginCriticalRegion();
        try {
            if (lockEntered) {
                self.ExitReadLock();
            }
        }
        finally {
            Thread.EndCriticalRegion();
        }
    }

    return result;
}
\$\endgroup\$
4
  • \$\begingroup\$ In cases like this, I prefer methods that work with using, instead of taking a delegate. \$\endgroup\$
    – svick
    Commented Nov 28, 2012 at 17:29
  • \$\begingroup\$ @svick, but working with using is not fully thread-safe :( \$\endgroup\$
    – TcKs
    Commented Nov 29, 2012 at 0:17
  • \$\begingroup\$ What do you mean? I don't see any reason why it shouldn't be thread-safe (assuming you don't use it incorrectly). \$\endgroup\$
    – svick
    Commented Nov 29, 2012 at 0:31
  • \$\begingroup\$ @svick: its because the using(var x = SomeFunc()){...} is only syntax sugar, when ThreadAbortException is thrown before object is passed from return value of "SomeFunc()" to local variable "x", the "finally{...}" block will not handle passed object, because in "x" is nothing (null). \$\endgroup\$
    – TcKs
    Commented Dec 14, 2012 at 18:02

1 Answer 1

3
\$\begingroup\$

It looks pretty good. I can't see anything less than great.
I'd just add that to your code:

    private static void Critical(Action criticalAction)
    {
        try
        {
            Thread.BeginCriticalRegion();
            criticalAction();
        }
        finally
        {
            Thread.EndCriticalRegion();
        }
    }

And i used the IsWriteLockHeld, IsReadLockHeld, etc, before exiting the lock.

\$\endgroup\$
2
  • \$\begingroup\$ Good point. Didn't you mean the "Thread.BeginCriticalRegion()" should be before "criticalAction()". \$\endgroup\$
    – TcKs
    Commented Dec 14, 2012 at 18:03
  • \$\begingroup\$ You got a point, there! \$\endgroup\$ Commented Dec 14, 2012 at 18:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.