问题
MSDN Documentation and many examples of using ReaderWriterLockSlim
class recommends using the following pattern:
cacheLock.EnterWriteLock();
try
{
//Do something
}
finally
{
cacheLock.ExitWriteLock();
}
But I'm curious if it's completely safe. Is it possible that some exception will happen after lock is acquired, but before the try
statement so that lock is stuck in the locked state? The most obvious candidate is ThreadAbortException
. I understand that probability of this situation is extreemely small, but the consequences are extreemely bad - so I think it worth thinking about it. I don't believe compiler understands this pattern and prevents processor from interrupting thread before try
statement.
If there is theoretical possibility that this code is unsafe, and is there ways to make it safer?
回答1:
It can be an issue and apparently is in some high-load scenarios. This article goes into it further, but it basically boils down to using an empty try block coupled with a finally to acquire & release the lock:
var lockIsHeld = false;
try {
try {
}
finally {
rwl.EnterReadLock();
lockIsHeld = true;
}
// Do work here
}
finally {
if (lockIsHeld) {
rwl.ExitReadLock();
}
}
This approach guarantees that your lock is always acquired and release as finally blocks are guaranteed to run even in the case of a ThreadAbortException
.
Other exceptions are detailed in @hvd's post.
Personally I wouldn't worry about it unless you actually see this issue in the wild...
回答2:
There are only three ways this could theoretically fail that I can think of:
ThreadAbortException
you mentioned already. This is fairly easy to handle correctly: just make sure you never callThread.Abort()
. You almost certainly don't need to; there are almost always better ways of achieving the desired result.Only if you really, really, really need to call it, and the thread you're aborting is the one with a risk of keeping a lock open, place your entire block of code (from
Enter
toExit
) in atry
...finally
clause where the try-block is empty.Thread.Abort()
will throw theThreadAbortException
only when the currentfinally
handler finishes.StackOverflowException
is another possibility. It may happen during the call toExitWriteLock
. This is also fairly easy: when a stack overflow happens, the process is terminated. You cannot catch or handle this. Since the process is terminated, no other thread in your process will be keeping any lock open.OutOfMemoryException
might theoretically be thrown during the call toExitWriteLock
. UnlikeStackOverflowException
, this one is theoretically catchable. If you don't catch it, again the process will be terminated, and no other thread in your process will be keeping any lock open. If you do catch it, however, you cannot hope to handle this correctly, and chances are, your other threads will soon start throwing this exception as well.
In short, I wouldn't worry about it.
来源:https://stackoverflow.com/questions/24533104/is-it-completely-safe-to-use-pattern-of-readerwriterlockslim-enterxxx-with-con