Как я могу использовать RWLock для реализации сценария много читателей-писателей правильно? - PullRequest
1 голос
/ 20 июня 2019

Я пытаюсь написать метод, который обрабатывает некоторые сообщения.Их можно читать или писать сообщения.Параллельное чтение разрешено, но при получении блокировки write все последующие блокировки чтения должны ждать, пока не будет снята блокировка записи.Так что я ReaderWriterLockSlim это то, что мне нужно.Но когда я пытаюсь реализовать простое приложение, чтобы увидеть, работает ли оно должным образом, я получаю Recursive read lock acquisitions not allowed in this mode исключение.

Вот мой пример, чтобы показать, как оно должно работать:

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);

Ожидаемый результат: 100 строк Readonly task start, одна строка Write task start, затем 100 строк Readonly task done, затем одна строка Write task done, затем печатается остальная часть программы.

Фактический результат:

Readonly task start
Readonly task done

LockRecursionException4
Recursive read lock acquisitions not allowed in this mode. 

Я не понимаю, где здесь появляется рекурсия.Я просто вызываю одну функцию без какой-либо рекурсии.Я читаю статьи, но не вижу, как это работает.

...