Страницы

Поиск по вопросам

суббота, 4 января 2020 г.

Возможно ли снять блокировку из другого потока?

#net #многопоточность


При попытке снять блокировку монитора из другого потока выбрасывается исключение


  An unhandled exception of type 'System.Threading.SynchronizationLockException'
occurred in Test - Smth.exe
  
  Additional information: Для не синхронизированного блока кода вызван метод синхронизации
объектов.


Пример кода:

Imports System.Threading

Module All
  Sub Main()
    Dim Obj As New Object

    Monitor.Enter(Obj)
    Call (New Thread(Sub() Monitor.Exit(Obj))).Start()

    Console.ReadKey()
  End Sub
End Module


Возможно ли как-то снять блокировку из того потока, который её НЕ устанавливал?
    


Ответы

Ответ 1



С монитором — нет, никак. Насколько я понимаю, единственный синхронизационный примитив, который позволяет разблокировать себя из другого потока — это Semaphore (лучше брать рекомендованный вариант SemaphoreSlim). Пример (на C#) var sema = new SemaphoreSlim(0); // создаём заблокированный семафор new Thread(() => { sema.Release(); // разблокируем его // ... }).Start(); sema.Wait(); // ожидаем разблокировки Если вы хотите просто дождаться реального старта другого потока, можно использовать ManualResetEventSlim. Код практически такой же: var ev = new ManualResetEventSlim(initialState: false); new Thread(() => { ev.Set(); // ... }).Start(); ev.Wait(); Поправка: всё-таки исходную проблему можно решить с монитором, если заставить его работать как conditional variable. Код получается немного более сложным, и требует вспомогательной булевой переменной: bool started = false; object mutex = new object(); new Thread(() => { lock (mutex) { started = true; Monitor.Pulse(mutex); } // ... }).Start(); lock (mutex) { while (!started) Monitor.Wait(mutex); // блокировка будет отпущена на период ожидания } И наконец, если не только основному потоку нужно дождаться порождённый поток, но и наоборот, порождённый поток должен задержаться до тех пор, пока основной поток не узнает, что он стартовал, у нас возникает так называемая задача рандеву: синхронизация одной точки выполнения у нескольких потоков. Это проще всего делать при помощи Barrier: var barrier = new Barrier(participantCount: 2); new Thread(() => { barrier.SignalAndWait(); // (*) // ... }).Start(); barrier.SignalAndWait(); // (*) Строки, отмеченные звёздочкой, будут ждать друг друга: первый из пришедших в эту строку потоков затормозится до прихода второго.

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

Отправить комментарий