What I need to achieve is:
(Link to used AsyncLock).
private async Task MasterAsync()
{
using (await _asyncLock.LockAsync())
{
await Task.Delay(2000);
}
}
private async Task HumbleSlave1Async()
{
using (await _asyncLock.LockAsync())
{
await Task.Delay(5000);
}
}
private async Task HumbleSlave2Async()
{
using (await _asyncLock.LockAsync())
{
await Task.Delay(5000);
}
}
I am not sure how to solve it, was thinking about use of two different locks for each slave in MasterAsync but then one lock would be in another:
private async Task MasterAsync()
{
using (await _asyncLock1.LockAsync())
{
using (await _asyncLock2.LockAsync())
{
await Task.Delay(2000);
}
}
}
private async Task HumbleSlave1Async()
{
using (await _asyncLock1.LockAsync())
{
await Task.Delay(5000);
}
}
private async Task HumbleSlave2Async()
{
using (await _asyncLock2.LockAsync())
{
await Task.Delay(5000);
}
}
Does it make sense and is it safe(deadlocks, etc...) especially when I used AsyncLock ?
When MasterAsync is executing, HumbleSlave1Async and HumbleSlave2Async can NOT. Vice Versa- When one or both of Slaves are executing, MasterAsync can NOT. Difficult part- Slaves can NOT block each other.
First, double-check whether you really want this. The majority of the time, a restructuring of the code responsibilities will simplify what synchronization you need (and is usually more efficient, too).
That said, your scenario fits a reader/writer lock. A RWL is a lock that can be taken two different ways, as a "writer" (which does not allow any other locks at the same time) or as a "reader" (which allows other readers but not writers). Stephen Toub has an async-compatible one here and I have one as part of my AsyncEx library.
Update: Example code:
private readonly AsyncReaderWriterLock _lock = new AsyncReaderWriterLock();
private async Task MasterAsync()
{
using (await _lock.WriterLockAsync())
{
await Task.Delay(2000);
}
}
private async Task HumbleSlave1Async()
{
using (await _lock.ReaderLockAsync())
{
await Task.Delay(5000);
}
}
private async Task HumbleSlave2Async()
{
using (await _lock.ReaderLockAsync())
{
await Task.Delay(5000);
}
}
A possible problem with your approach is that when HumbleSlave2Async is executing, and MasterAsync has been called, acquired asyncLock1 and is awaiting asyncLock2, you won't be able to execute HumbleSlave1Async (because asyncLock1 is taken by MasterAsync). So, your condition #3 will not be satisfied.
Maybe you should use something like AsyncManualResetEvent to make this work.
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