views:

45

answers:

1

This is a theoretical question; I don't have an actual issue to solve, I just want to understand the reasoning behind the way this works.

I found out that if a thread omits to exit a ReaderWriterLock then other threads will fail to acquire a lock even after the original thread terminates. Is there a good reason why ReaderWriterLock does not grant the lock to waiting threads as soon as the thread that owns the lock terminates?

Here is a test case that demonstrate the issue.

    static void Main(string[] args)
    {
        ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim();

        Thread t1 = new Thread((a) =>
        {
            readerWriterLock.EnterReadLock();

            // this thread omits to Exit the lock....
        });

        Thread t2 = new Thread((a) =>
        {
            readerWriterLock.EnterWriteLock();
        });

        t1.Start();
        t2.Start();

        // wait for all threads to finish
        t1.Join();
        t2.Join();
    }
+3  A: 

The simple answer: There is no easy way for the writer thread to know that the reader threads have terminated, without also making the locking operations expensive.

Locks are usually implemented as values in memory, so acquiring an releasing the lock involve changing these values. If a thread sets the value to acquire the lock, then crashes, the only way another lock can be acquired is if you have some background thread that polls for dead threads, looks at their list of recently acquired locks, and cleans them up.

In addition to this being expensive and needing a lot of plumbing, it is potentially unsafe because you don't know exactly how far the thread got before it crashed.

0xfe
In the context of a thread that crashed, I agree that assuming the resource it locked is now in a clean state would be risky. But in the context of a normal thread termination, I think such assumption would be safe. Regarding performance, they could provide two implementations: the one we have now and a slower but smarter one that implements auto release. Anyhow, thank you for your answer, I think what you explained is indeed the reason why it is done that way.
Sly
Re: normal thread termination, you can consider using an RAII pattern for locks, which help ensure that a lock is released upon exiting some scope. In C#, you can use the _lock_ keyword (for regular locks) or _try/finally_ blocks (for your ReaderWriterLock) to ensure that locks get released upon scope exit. Again, this won't help you if the thread crashed, or if it called some lower-level thread-exit function, but it will help reduce the risk of deadlocks from programming errors where you forget to release the lock on some convoluted code path.
0xfe