I have two async functions, which I will call ChangeState() and DoThing(). Each of them awaits downstream async methods. These are called are from event handlers, so they will not block any other code while they execute. If ChangeState() is called, it's imperative that DoThing() does not do its thing until any previous ChangeState() has completed. ChangeState() could be called again while it's still executing. Any executions started before DoThing() should be completed before DoThing() can continue.
The reverse is also true; ChangeState() should wait until any previously running DoStuff() is complete.
How can I implement this without the danger of deadlocks?
I know awaits are not allowed inside of lock statements and that's for good reasons, which I why I'm not trying to recreate that functionality.
async void ChangeState(bool state)
{
//Wait here until any pending DoStuff() is complete.
await OutsideApi.ChangeState(state);
}
async void DoStuff()
{
//Wait here until any pending ChangeState() is complete.
await OutsideApi.DoStuff();
}
By your requirements seems something like ReaderWriterLock could help you. Also, since you have async methods you should use async lock. Unfortunately, there is no await ready ReaderWriterLock lock provided by the .NET framework itself. Luckily, you could take a look at the AsyncEx library or this article. The example using AsyncEx.
var readerWriterLock = new AsyncReaderWriterLock();
async void ChangeState(bool state)
{
using(await readerWriterLock.ReaderLockAsync())
{
await OutsideApi.ChangeState(state);
}
}
async void DoStuff()
{
using(await readerWriterLock.WriterLockAsync())
{
await OutsideApi.DoStuff();
}
}
n.b. This solution still has the limitation that DoStuff calls could not be concurrent, writer lock, but still the order of the calls and the requirement to finalize all DoStuff before ChangeState and vice versa will be fulfilled.(tip from @Scott Chamberlain to use both reader and writer lock)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With