#c_sharp #многопоточность
Всем привет. Подскажите пожалуйста почему идет запуск методов в потоках именно в
таком порядке. Вот код:
using System;
using System.Threading;
class a
{
object o = new object();
public void Test()
{
lock (o)
{
Console.WriteLine("Start");
Monitor.Wait(o);
Console.WriteLine("Stop");
}
}
public void UnLock()
{
lock(o)
Monitor.Pulse(o);
Console.WriteLine("Unlock");
for(int x = 0; x <10; x++)
{
Thread.Sleep(500);
Console.WriteLine(x);
}
}
}
class b
{
static void Main()
{
a A = new a();
Thread t = new Thread(A.Test);
t.Start();
Thread t1 = new Thread(A.UnLock);
t1.Start();
}
}
Я ожидаю что вначале запустится Test, потом написав слово Start он останавливается,
потом запускается метод UnLock и при вызове в нем Pulse() метод Test не должен продолжать
свое дело, так как Pulse() не снимает блокировку с объекта, однако как только вызывается
Pulse(), то несмотря на заблокированный объект в методе Unlock, метод Test начинает
продолжать свое дело. Почему так?? То есть я ожидаю вывод такой
Start
Unlock
0....9
Stop
а получается
Start
Unlock
Stop
0....9
То есть видно, что метод Pulse говорит о освобождении объекта блокировки, и не смотря
на то что он не освободился по факту, метод Test продолжает свою работу
Ответы
Ответ 1
У вас в коде две проблемы. Первая - неправильный отступ. У вас сейчас на самом деле написано следующее: public void UnLock() { lock(o) { Monitor.Pulse(o); } Console.WriteLine("Unlock"); for(int x = 0; x <10; x++) { Thread.Sleep(500); Console.WriteLine(x); } } как указал Pavel Mayorov, вы освобождаете лок сразу же после вызова Pulse. Вторая - само предположение, что второй поток будет запущен позже. Это многопоточность, и нет никаких гарантий что Test начнет выполнятся до UnLock. Даже починив lock, при определенном положении звезд, вы вполне можете получить вывод: Unlock 0....9 Start и зависание на Wait.Ответ 2
Сразу после вызова Pulse вы освобождаете блокировку, выходя из блока lock(o) - вот первый поток и продолжает работу.Ответ 3
Из документации: Поток, который в данный момент владеет блокировкой указанного объекта, вызывает этот метод для сообщения следующему в очереди потоку о блокировке. При получении импульса ожидающий поток перемещается в очередь готовности. Когда поток, вызвавший метод Pulse, освобождает блокировку, следующий поток в очереди готовности (который необязательно является потоком, получившим импульс) получает блокировку. Т.е. поскольку вы берете лок только на вызов метода Pulse(), то Test() продолжает работу сразу после того, как освобождается блокировка в Unlock(). Чтобы исправить это, блокировку надо брать на весь код: public void UnLock() { lock(o) { Monitor.Pulse(o); Console.WriteLine("Unlock"); for(int x = 0; x <10; x++) { Thread.Sleep(500); Console.WriteLine(x); } } } (И логичнее будет вызывать Pulse() после цикла.) Но у вас есть еще одно неверное предположение: что метод Test() будет запущен раньше, чем Unlock(). Это необязательно так. Первым может запуститься метод Unlock().
Комментариев нет:
Отправить комментарий