Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it Safe to use ReaderWriterLockSlim in an async method

Since the ReaderWriterLockSlim class uses Thread ID to see who owns the lock is it safe to use with async methods where there is no guarentee that all the method will be executed on the same thread.

For example.

    System.Threading.ReaderWriterLockSlim readerwriterlock = new System.Threading.ReaderWriterLockSlim();     private async Task Test()     {         readerwriterlock.EnterWriteLock();         await Task.Yield(); //do work that could yield the task         readerwriterlock.ExitWriteLock(); //potentailly exit the lock on a different thread     } 
like image 303
user1937198 Avatar asked Apr 08 '13 15:04

user1937198


2 Answers

Is it Safe to use ReaderWriterLockSlim in an async method

Yes and no. It can be safe to use this in an async method, but it is likely not safe to use it in an async method where you enter and exit the lock spanning an await.

In this case, no, this is not necessarily safe.

ExitWriteLock must be called from the same thread that called EnterWriteLock. Otherwise, it throws a SynchronizationLockException. From the documentation, this exception is thrown when:

The current thread has not entered the lock in write mode.

The only time this would be safe is if this was used in an async method which was always in an environment where there was a current SynchronizationContext in place which will move things back to the same thread (ie: Windows Forms, WPF, etc), and wasn't used by a nested async call where a "parent" up the call chain setup a Task with ConfigureAwait(false) (which would prevent the Task from capturing the synchronization context). If you are in that specific scenario, you'd know the thread would be maintained, as the await call would marshal you back onto the calling context.

like image 109
Reed Copsey Avatar answered Sep 22 '22 18:09

Reed Copsey


No. Thread-affine coordination primitives should not be used as in your example.

You correctly identified the problem where a different thread can be used to resume after the await. There is another issue due to the the way async methods return early: the caller is not aware that the lock is held.

ReaderWriterLockSlim by default is a non-recursive lock, so if another async method attempts to take the same lock, you'll get a deadlock. Even if you make the lock recursive, you'll still end up with a problem: arbitrary end-user code should never be called while holding a lock, and that's essentially what you're doing when you use an await.

The SemaphoreSlim type is async-aware (via its WaitAsync method), and Stephen Toub has a series of async coordination primitives also available in my AsyncEx library.

like image 35
Stephen Cleary Avatar answered Sep 21 '22 18:09

Stephen Cleary