http://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystifiedMonitor.Pulse y Wait - Comportamiento inesperado
colas de espera:
La cola de listos es el conjunto de hilos que están a la espera de una cerradura especial . Los métodos Monitor.Wait presentan otra cola: la cola de espera . Esto es obligatorio ya que la espera de un Pulso es distinta de espera para adquirir un bloqueo. Al igual que la cola lista, la cola de espera es FIFO.
patrón Recomendado:
Estas colas pueden conducir a un comportamiento inesperado. Cuando se produce un pulso, se lanza el encabezado de la cola de espera y se agrega a la cola lista . Sin embargo, si hay otros subprocesos en la lista de espera, adquirirá el bloqueo antes de la secuencia que se lanzó. Este es un problema , porque el hilo que adquiere el bloqueo puede alterar el estado que depende del hilo pulsado. La solución es usar una condición while dentro de la instrucción de bloqueo
* Q = Queue.
Por eso, entiendo que cuando llamo al Pulse
, hace 2 cosas antes de que termine. En primer lugar, elimina un hilo de la Q en espera para la Q lista. En segundo lugar, permite que un hilo (sin saber quién es ese hilo) en el Ready Q adquiera el bloqueo; no importa quién adquiere el candado (el hilo que vino de la Q en espera o un hilo que estaba en la Q lista por algún motivo).
Si tengo razón en ese entonces por qué está poniendo un while
antes Monitor.Wait
ayudar a solucionar el problema (problema - el pulso termina incluso si el hilo que venía de la Q de espera no adquirió la cerradura)?
A. Dime si estoy en lo cierto con el propósito de Monitor.Pulse
.
B. ¿Por qué necesito para poner una while
antes Monitor.Wait
El código completo de la respuesta a continuación:
class Program
{
static Queue<int> queue = new Queue<int>();
static object someMonitor = new object();
static void Main(string[] args)
{
Thread Thread1 = new Thread(WorkAlltheTime);
Thread1.Name = "Thread1";
Thread Thread2 = new Thread(WorkAlltheTime);
Thread2.Name = "Thread2";
Thread Thread3 = new Thread(WorkOnce);
Thread3.Name = "Thread3";
Thread1.Start();
Thread2.Start();
Thread.Sleep(1000);
Thread3.Start();
Console.ReadLine();
}
static void WorkAlltheTime()
{
Console.WriteLine("Came in to Ready Q: " + Thread.CurrentThread.Name);
lock (someMonitor)
{
Console.WriteLine("Came out from Ready Q: " + Thread.CurrentThread.Name);
// Broken!
while (queue.Count == 0)
{
Console.WriteLine("Came in to Waiting Q: " + Thread.CurrentThread.Name);
Monitor.Wait(someMonitor);
Console.WriteLine("Came out from Waiting Q: " + Thread.CurrentThread.Name);
}
queue.Dequeue();
Console.WriteLine("Thread: "+Thread.CurrentThread.Name+" Pulled Out");
}
}
static void WorkOnce()
{
lock (someMonitor)
{
queue.Enqueue(1);
Monitor.Pulse(someMonitor);
}
}
}
Gracias, escribí el código completo de su ejemplo y con su explicación lo probé 90 veces y lo entiendo completamente ahora. Gracias Agian! –