2015-03-19 2 views
1

У меня была проблема, с которой я сводился к этому минимальному тестовому сценарию, и все же я не понимаю, почему он не работает должным образом. Код здесь прост: родительский поток получает блокировку, затем запускает дочерний элемент, затем освобождает блокировку, начиная с нее. Затем продолжается дочерний поток, который был заблокирован на одном и том же замке, освобождает родителя, затем спит в течение пяти секунд.C#: Monitor.Pulse() не работает

using System.Threading; 
using System; 
using System.IO; 
using System.Diagnostics; 

namespace Test 
{ 
    class MainClass 
    { 
     public static void Main(string[] args) 
     { 
      Object waitForThrToStart = new Object(); 
      lock (waitForThrToStart) 
      { 
       new Thread(() => 
       { 
        lock (waitForThrToStart) 
        { 
         Debug.WriteLine("2. Child: free the parent"); 
         Monitor.Pulse(waitForThrToStart); 
         Debug.WriteLine("3. Child: pulsed ☺ Now sleep"); 
         Thread.Sleep(5000); 
         Debug.WriteLine("5. Child: time out"); 
        } 
       }).Start(); 
       Debug.WriteLine("1. Parent: waiting"); 
       Monitor.Wait(waitForThrToStart); 
       Debug.WriteLine("4. Parent: awoke, exiting now"); 
      } 
     } 
    } 
} 

Прекрасно, кроме этого ... он не работает. Родитель освободили только после того, как пять секунд, когда ребенок вышел, вы можете увидеть его на выходе:

1. Parent: waiting 
2. Child: free the parent 
3. Child: pulsed ☺ Now sleep 
5. Child: time out 
4. Parent: awoke, exiting now 

Я даже попытаться использовать Monitor.PulseAll(), что ничего не изменилось. Также я подумал, что, возможно, по какой-то странной причине ребенок получил копию объекта, поэтому они работают с разными переменными. Но я опроверг это, установив вызов Sleep() у родителя - ребенок наверняка ждал блокировки.

Что это, это ошибка? Есть ли обходной путь?

+0

«Есть ли обходной путь?» - не используйте 'Pulse' /' Wait'. Независимо от * проблемы *, которую вы пытаетесь решить, почти наверняка есть лучший способ ее решения, и обычно это будет на более высоком уровне примитивы синхронизации потоков. –

+0

И это [документальное поведение] (https://msdn.microsoft.com/en-us/library/system.threading.monitor.pulse%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396): «Когда поток, который вызывается« Pulse »**, освобождает блокировку **, следующий поток в очереди готовности (который не обязательно является импульсом) получает блокировку». (Мой акцент) –

+0

@Damien_The_Unbeliever ну, в реальном коде у меня есть поток, который хвастается несколькими другими потоками, которые выполняют некоторую работу. Затем родительский поток должен подождать некоторое время, пока один из детей не будет сигнализировать, либо просто уходите, если время ожидания. Я понятия не имею, как сделать эту работу по-другому. –

ответ

3

Вы пульсируете монитор у ребенка, но вы также заблокировали его. Wait вернется только после того, как вы отпустили блокировку в дочернем потоке, после чего ему нужно будет восстановить блокировку перед возвратом.

+1

Действительно, это сработало! Это снова не было ни очевидным, ни даже логичным; Я никогда не устаю удивляться API-интерфейсу .net. –

 Смежные вопросы

  • Нет связанных вопросов^_^