recibir una notificación cuando todos los subprocesos del grupo de subprocesos en segundo plano hayan finalizado

StackOverflow https://stackoverflow.com/questions/358721

  •  21-08-2019
  •  | 
  •  

Pregunta

Tengo un escenario cuando inicio 3..10 subprocesos con ThreadPool.Cada hilo hace su trabajo y regresa al ThreadPool.¿Cuáles son las posibles opciones para recibir notificaciones en el hilo principal cuando todos los hilos en segundo plano hayan finalizado?

Actualmente estoy usando un método propio que incrementa una variable para cada uno de los subprocesos creados y la disminuye cuando un subproceso en segundo plano está a punto de finalizar.Esto funciona bien, pero tenía curiosidad por saber si hay mejores opciones.

¿Fue útil?

Solución

decrementar una variable (entre hilos) es un poco arriesgado si no realiza con Interlocked.Decrement, pero que el enfoque debe estar bien si tiene el último hilo (es decir, cuando se pone a cero) generar un evento. Tenga en cuenta que tendría que estar en un bloque de "fin" para evitar perderlo en el caso de las excepciones (además de que no quieren matar el proceso).

En "Extensiones" en paralelo (o con .NET 4.0), es posible que también mira a los Parallel.ForEach opciones aquí ... que podría haber otra manera de conseguir todo lo hecho como un bloque. Sin tener que mirar a todos ellos de forma manual.

Otros consejos

Prueba esto: https://bitbucket.org/nevdelap/poolguard

using (var poolGuard = new PoolGuard())
{
    for (int i = 0; i < ...
    {
        ThreadPool.QueueUserWorkItem(ChildThread, poolGuard);
    }
    // Do stuff.
    poolGuard.WaitOne();
    // Do stuff that required the child threads to have ended.

void ChildThread(object state)
{
    var poolGuard = state as PoolGuard;
    if (poolGuard.TryEnter())
    {
        try
        {
            // Do stuff.
        }
        finally
        {
            poolGuard.Exit();
        }
    }
}

Múltiples PoolGuards se pueden utilizar de diferentes maneras para realizar un seguimiento de las discusiones cuando han terminado, y se ocupa de temas que no han comenzado cuando la piscina ya está cerrado.

Si sus no más de 64 hilos que esperar en, puede utilizar el método WaitHandle.WaitAll como esto:

List<WaitHandle> events = new List<WaitHandle>();
for (int i = 0; i < 64; i++)
{
    ManualResetEvent mre = new ManualResetEvent(false);
    ThreadPool.QueueUserWorkItem(
        delegate(object o)
        {
            Thread.Sleep(TimeSpan.FromMinutes(1));
            ((ManualResetEvent)o).Set();
        },mre);
    events.Add(mre);
}
WaitHandle.WaitAll(events.ToArray());

La ejecución esperará hasta que se fijan todos los ManualResetEvents, de forma alternativa, puede utilizar el método WaitAny.

Los métodos WaitAny y WaitAll bloquearán la ejecución, pero se puede usar simplemente la lista, o un diccionario de ManualResetEvents vinculados a la tarea que es la freza para después determinar si el hilo se hace sin embargo.

Hay no es un mecanismo incorporado para realizar esta acción en el momento -. Me parece uno de los mayores dolores sobre el uso de subprocesos de grupo

Como dice Marc, este es el tipo de cosas que está siendo fijado en extensiones paralelas / .NET 4.0.

¿No podrías darle a cada hilo un ManualResetEvent distinto y hacer que cada uno configure el evento cuando termine?Luego, en el hilo principal puedes esperar todos los eventos pasados.

La solución de Marc es mejor si lo que desea saber cuándo se terminan todos los puestos de trabajo, y no necesita información más fino que (como parece ser el caso).

Si quieres un poco de hilo para desovar puestos de trabajo, y algún que otro hilo para recibir las notificaciones, se puede usar WaitHandle. El código es mucho más largo.

    int length = 10;
    ManualResetEvent[] waits = new ManualResetEvent[length];
    for ( int i = 0; i < length; i++ ) {
        waits[i] = new ManualResetEvent( false );
        ThreadPool.QueueUserWorkItem( (obj) => {
            try {

            } finally {
                waits[i].Set();
            }
        } );
    }

    for ( int i = 0; i < length; i++ ) {
        if ( !waits[i].WaitOne() )
            break;
    }

El método WaitOne, como está escrito, siempre devuelve cierto, pero lo he escrito así para que se recuerde que algunas sobrecargas toman un tiempo de espera como argumento.

¿Qué pasa con el uso del semáforo, y establecer un límite a él tanto como su grupo de subprocesos. Tener un método para buscar un semáforo, que se llamará cuando se inicia el hilo, lo liberan cuando el extremo del hilo y provocar un evento si ha tomado todo el semáforo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top