#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().
Комментариев нет:
Отправить комментарий