При попытке снять блокировку монитора из другого потока выбрасывается исключение
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
Возможно ли как-то снять блокировку из того потока, который её НЕ устанавливал?
Ответ
С монитором — нет, никак.
Насколько я понимаю, единственный синхронизационный примитив, который позволяет разблокировать себя из другого потока — это 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(); // (*)
Строки, отмеченные звёздочкой, будут ждать друг друга: первый из пришедших в эту строку потоков затормозится до прихода второго.
Комментариев нет:
Отправить комментарий