Критический раздел — только один поток «спит» при блокировке

#c# #multithreading #locking #critical-section

#c# #многопоточность #блокировка #критический раздел

Вопрос:

У меня есть критический раздел (с использованием lock области редактирования).

Я бы хотел, чтобы на нем «спал» только последний входящий поток. Следовательно, как только критическая секция заблокирована, каждый входящий поток «завершает» все предыдущие спящие потоки.

Есть ли способ добиться этого с помощью C #?

Спасибо

Комментарии:

1. lock использует Monitor класс под капотом, вы можете попытаться получить желаемое поведение, используя Monitor или Semaphore

2. Можете ли вы определить, что должно произойти с другими потоками?

3. @MoB. другие потоки завершаются и собираются GC

Ответ №1:

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

 public class SingleWaiterLock
{
    private bool realLockTaken = false;
    private TaskCompletionSource<bool> waiterTCS = null;
    private object lockObject = new object();

    public Task<bool> WaitAsync()
    {
        lock (lockObject)
        {
            if (!realLockTaken)
            {
                realLockTaken = true;
                return Task.FromResult(true);
            }
            if (waiterTCS == null)
            {
                waiterTCS = new TaskCompletionSource<bool>();
                return waiterTCS.Task;
            }
            else
            {
                waiterTCS.SetResult(false);
                waiterTCS = new TaskCompletionSource<bool>();
                return waiterTCS.Task;
            }
        }
    }

    public void Release()
    {
        lock (lockObject)
        {
            if (waiterTCS != null)
            {
                waiterTCS.SetResult(true);
                waiterTCS = null;
            }
            else
            {
                realLockTaken = false;
            }
        }
    }
}
 

Логическое значение, возвращаемое методом ожидания, указывает, действительно ли вы получили блокировку (если она возвращает true) или были загружены кем-то, кто придет позже (возвращает false). Блокировка должна быть снята (но всегда должна быть снята) только тогда, когда ожидание возвращает значение true.