I'm trying to write a method which process some messages. They can be read or write messages. Parallel reads are permitted, but when write
lock is aquired all subsequent read lock should wait until write lock is released. So I thught ReaderWriterLockSlim
is what I need. But when I'm trying to implement simple application to see if it works as expected I get Recursive read lock acquisitions not allowed in this mode
exception.
Here is my example to show how it's intended to work:
ReaderWriterLockSlim distributionLock = new ReaderWriterLockSlim();
async Task ExecuteReadLockTaskAsync(Func<Task> taskFunc)
{
distributionLock.EnterReadLock();
try
{
await taskFunc();
}
finally
{
if (distributionLock.IsReadLockHeld)
{
distributionLock.ExitReadLock();
}
}
}
async Task ExecuteWriteLockTaskAsync(Func<Task> taskFunc)
{
distributionLock.EnterWriteLock();
try
{
await taskFunc();
}
finally
{
if (distributionLock.IsWriteLockHeld)
{
distributionLock.ExitWriteLock();
}
}
}
Task ProcessAsync(bool flag)
{
switch (flag)
{
case false:
return ExecuteReadLockTaskAsync(() =>
{
Console.WriteLine("Readonly task start");
return Task.Delay(1000).ContinueWith(t => Console.WriteLine("Readonly task done"));
});
case true:
return ExecuteWriteLockTaskAsync(() =>
{
Console.WriteLine("Write task start");
return Task.Delay(3000).ContinueWith(t => Console.WriteLine("Write task done"));
});
default:
throw new InvalidOperationException($"Unknown message typex");
}
}
var tasks= new List<Task>();
for (int i = 0; i < 100; i++)
{
tasks.Add(ProcessAsync(false));
}
tasks.Add(ProcessAsync(true));
for (int i = 0; i < 100; i++)
{
tasks.Add(ProcessAsync(false));
}
await Task.WhenAll(tasks);
Expected result: 100 lines of Readonly task start
, one line of Write task start
, then 100 lines of Readonly task done
, then one line of Write task done
, then the rest of program prints.
Actual result:
Readonly task start
Readonly task done
LockRecursionException4
Recursive read lock acquisitions not allowed in this mode.
I don't get where recursion appears here. I'm just calling one function, without any kind of recursion. I read articles but I don't see how it works here.