2010-03-29 18 views

Respuesta

51

Siempre que desee controlar la ejecución de varios subprocesos en su aplicación. Aunque esto no solo significa que solo un hilo incrementa el contador; pero deje que los hilos comiencen/detengan o pause sobre un evento.

Ver WaitHandles - Auto/ManualResetEvent and Mutex

--EDIT--

WaitHandle s son el mecanismoque "utiliza" para controlar la ejecución de los hilos. No se trata de identificadores que no sean accesibles dentro de un hilo; se trata de usarlos dentro del hilo.

Esto puede ser un ejemplo gordo, pero por favor tengan paciencia conmigo; Piense, una dama le da cinco silbatos diferentes a cinco niñas y les dice que suene cada vez que ocurra something; el proceso es para que cada niña pite un silbato, y la dama sabría quién hizo sonar el silbato.

Ahora, no se trata de compartir los silbidos unos con otros, se trata, probablemente, de que la dama los use para "controlar" la ejecución o el proceso de cómo las niñas pitan el silbato.

Por lo tanto, técnicamente, el proceso sería:

  1. crear un evento de espera (ManualResetEvent objeto)
  2. registrar los eventos, WaitHandle.WaitAny(events);
  3. Después de que haya terminado la operación se realiza en el hilo, el .Set() , lo que le diría al WaitHandle que '¡ya terminé!'.

Por ejemplo, considere el ejemplo del enlace proporcionado. He agregado los pasos para que entiendas la lógica. Estos no son los pasos codificados, pero solo para que pueda entender.

class Test 
{ 
    static void Main() 
    { 
    //STEP 1: Create a wait handle 
     ManualResetEvent[] events = new ManualResetEvent[10];//Create a wait handle 
     for (int i=0; i < events.Length; i++) 
     { 
      events[i] = new ManualResetEvent(false); 
      Runner r = new Runner(events[i], i); 
      new Thread(new ThreadStart(r.Run)).Start(); 
     } 

    //STEP 2: Register for the events to wait for 
     int index = WaitHandle.WaitAny(events); //wait here for any event and print following line. 

     Console.WriteLine ("***** The winner is {0} *****", 
          index); 

     WaitHandle.WaitAll(events); //Wait for all of the threads to finish, that is, to call their cooresponding `.Set()` method. 

     Console.WriteLine ("All finished!"); 
    } 
} 


class Runner 
{ 
    static readonly object rngLock = new object(); 
    static Random rng = new Random(); 

    ManualResetEvent ev; 
    int id; 

    internal Runner (ManualResetEvent ev, int id) 
    { 
     this.ev = ev;//Wait handle associated to each object, thread in this case. 
     this.id = id; 
    } 

    internal void Run() 
    { 
    //STEP 3: Do some work 
     for (int i=0; i < 10; i++) 
     { 
      int sleepTime; 
      // Not sure about the thread safety of Random... 
      lock (rngLock) 
      { 
       sleepTime = rng.Next(2000); 
      } 
      Thread.Sleep(sleepTime); 
      Console.WriteLine ("Runner {0} at stage {1}", 
           id, i); 
     } 

    //STEP 4: Im done! 
     ev.Set(); 
    } 
} 
+0

WaitAll() - se utiliza para esperar a que todos los identificadores de un conjunto estén libres/señalizados ... ¿Significa que Handles no estará accesible para otros subprocesos hasta que no sean liberados (otros hilos deberían esperar para estas manijas en el conjunto)? – DotNetBeginner

+1

@DotNetBeginner: '¿Significa que Handles no será accesible para otros hilos'; por favor vea mi publicación actualizada, un ejemplo agregado solo para responder a esta pregunta. –

+0

Vale la pena decir que 'ev.Set()' mejor para poner en el bloque 'finally' –

6

La idea detrás de los métodos WaitAll y WaitAny es que son útiles cuando tiene muchas tareas que desea ejecutar en paralelo.

Por ejemplo, supongamos que tiene que realizar un trabajo que requiere que procese un poco los 1000 elementos de una matriz que deben procesarse en paralelo. Un típico Core 2 Duo + hyperthreading solo tiene 4 procesadores lógicos, por lo que no tiene mucho sentido tener más de 4 hilos al mismo tiempo (en realidad, sí, pero eso es una historia para otro momento, lo haremos pretender y usar el modelo simple de "un hilo por procesador" por ahora). Entonces 4 hilos, pero 1000 artículos; ¿qué haces?

Una opción es utilizar el método WaitAny. Lanzas 4 hilos, y cada vez que el método WaitAny regresa, comienzas otro, hasta que todos los 1000 elementos estén en cola. Tenga en cuenta que este es un ejemplo pobre para WaitAny, ya que también podría dividir su matriz en 250 bloques de elementos. Sin embargo, con suerte, te da una idea del tipo de situación en la que WaitAny es útil. Hay otras situaciones similares en las que WaitAny puede tener mucho sentido.

Pero ahora volvamos al escenario con 4 hilos que procesan 250 elementos de su matriz de 1000 elementos. Con esta opción, puede usar el método WaitAll para esperar a que finalice todo el procesamiento.

7

Es una clase abstracta, no la usa directamente. Las clases derivadas de hormigón son ManualResetEvent, AutoResetEvent, Mutex y Semaphore. Clases importantes en su caja de herramientas para implementar la sincronización de subprocesos. Heredan los métodos WaitOne, WaitAll y WaitAny, los usa para detectar que uno o más hilos señalaron la condición de espera.

El escenario de uso típico para Manual/AutoResetEvent es indicarle a un hilo que salga o dejar que un hilo indique que ha progresado a un punto de secuencia importante. Semaphore te ayuda a limitar el número de hilos que realizan una acción. O para implementar la sincronización de subprocesos que no debe tener afinidad con un hilo en particular. Mutex está ahí para asignar la propiedad a una sección de código a un hilo, la instrucción de bloqueo a menudo se aplica allí también.

Se han escrito libros sobre él. Joe Duffy's Concurrent Programming in Windows es lo último y lo mejor. Muy recomendable si piensas escribir código enhebrado.

27

WaitHandle es una clase base abstracta para los dos identificadores de eventos comúnmente utilizados: AutoResetEvent y ManualResetEvent.

Ambas clases permiten que un hilo "señalice" uno o más hilos. Se usan para sincronizar (o serializar la actividad) entre hilos. Esto se logra utilizando los métodos Set y WaitOne (o WaitAll). Por ejemplo:

Tema 1:

// do setup work 

myWaitHandle.Set(); 

Tema 2:

// do setup work 

myWaitHandle.WaitOne(); 

// this code will not continue until after the call to `Set` 
// in thread 1 completes. 

Este es un ejemplo muy rudimentario, y hay un montón de ellos disponibles en la web.La idea básica es que WaitOne se usa para esperar una señal de otro hilo que indique que algo ha sucedido. En el caso de AsyncWaitHandle (que se devuelve al invocar un delegado de forma asíncrona), WaitOne le permite hacer que el subproceso actual espere hasta que se complete la operación asincrónica.

Cuando AutoResetEvent o ManualResetEvent no están configurados, las llamadas a WaitOne bloquearán el hilo de llamada hasta que se llame al Set. Estas dos clases se diferencian solo en que AutoResetEvent "desactiva" el evento una vez que se completa una llamada exitosa a WaitOne, haciendo que las llamadas subsiguientes se bloqueen nuevamente hasta que se llame al Set. ManualResetEvent debe ser "desarmado" explícitamente llamando al Reset.

WaitAll y WaitAny son métodos estáticos en la clase WaitHandle que le permiten especificar una serie de WaitHandles que esperar en. WaitAll bloqueará hasta todos de los identificadores provistos son Set, mientras que WaitAny solo bloqueará hasta uno de ellos obtiene Set.

1

Aquí hay algunas respuestas muy largas.Para cualquiera que busque la respuesta corta:

Wait handle es un mecanismo para hacer que un hilo espere hasta que otro hilo llegue a cierto punto.

También puede tener varios hilos en espera y/o varios hilos que se están esperando, de ahí los métodos WaitOne, WaitAll y WaitAny. También hay varias opciones de semántica disponibles al elegir una de estas clases: Mutex, Semaphore, ManualResetEvent, AutoResetEvent que están bien documentadas.

Cuestiones relacionadas