2010-10-13 11 views
5

cómo hacer que el hilo de primer plano espere a que todos los hilos de fondo (secundarios) terminen en C#? Necesito obtener una lista de trabajos pendientes de la cola (base de datos), iniciar un nuevo hilo para ejecutar cada uno de ellos y finalmente esperar a que terminen todos los hilos hijo. cómo hacer eso en C#? Gracias por adelantado.cómo esperar a que finalicen todos los hilos de fondo (en C#)?

+2

posible duplicado de [C# freza varios subprocesos para trabajar y esperar hasta que todo termine] (http://stackoverflow.com/questions/2528907/c-spawn-multiple-threads-for-work-then-wait-until-all-finished) –

+0

gracias por todas las respuestas rápidas a mi pregunta – RKP

+0

has intentado [EventWaitHandle();] (http://msdn.microsoft.com/en-us/library/system.threading.eventwaithandle.aspx) – Bonshington

Respuesta

1

Considere el uso de ThreadPool. La mayoría de lo que quieres ya está hecho. Hay un example from Microsoft que hace prácticamente toda tu tarea. Reemplace "fibonacci" por "tarea de base de datos" y suena como su problema.

+0

Leí este artículo hace unos minutos y estaba a punto de responder diciendo que esa es la solución que estaba buscando. gracias por la respuesta. – RKP

7

Puede almacenar cada hilo lanzado en una matriz. Luego, cuando necesite esperar a todos, llame al método Unir en cada hilo de una matriz en un bucle.

Thread child = new Thread(...); 
Threads.Add(child); 
child.Start() 

... 

foreach(Thread t in Threads) 
{ 
    t.Join(); 
} 

HTH

+0

Gracias por la respuesta. Creo que thread.Join método es bueno para un solo hilo o muy pocos número fijo de hilos. para varios hilos, creo que hay un método WaitAll, pero no pude encontrar un buen ejemplo de código para él. – RKP

+3

@RKP: Esperar a que todos los hilos terminen es lo mismo que esperarlos a su vez, ¿no es así? Hay una función de winapi WaitForMultipleObjects, pero no es C#, aunque puedes usarla, pero no veo sentido. –

1

Esto es código incompleto, pero ManualResetEvent obras para usted

var waitEvents = new List<ManualResetEvent>(); 
foreach (var action in actions) 
{ 
    var evt = new ManualResetEvent(false); 
    waitEvents.Add(evt); 
    ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, TimeoutCallback, state, 5000, true); 
} 

if (waitEvents.Count > 0) 
    WaitHandle.WaitAll(waitEvents.ToArray()); 
+0

Gracias, pero ¿dónde se inicia el nuevo hilo para cada acción aquí en este código? ¿Es "5000" una configuración de tiempo de espera? – RKP

+0

Mire aquí el código completo, acabo de copiar un poco de una de mis respuestas anteriores: http://stackoverflow.com/questions/3915017/image-url-validation-in-c/3915440#3915440 – danijels

+0

Y sí, 5000 fue una configuración de tiempo de espera – danijels

0

Crear una estructura para realizar un seguimiento de sus subprocesos de trabajo

private struct WorkerThreadElement 
{ 
    public IAsyncResult WorkerThreadResult; 
    public AsyncActionExecution WorkerThread; 
} 

También es necesario realice un seguimiento del número total de subprocesos que se espera crear y la cantidad de subprocesos que tienen actualmente completado

private int _TotalThreads = 0; 
private int _ThreadsHandled = 0; 
private List<WorkerThreadElement> _WorkerThreadElements = new List<WorkerThreadElement>(); 

A continuación, cree un asa de autoreset para esperar la finalización del subproceso.

// The wait handle thread construct to signal the completion of this process 
private EventWaitHandle _CompletedHandle = new AutoResetEvent(false); 

También es necesario un delegado para crear nuevos temas - Hay varias formas de hacer esto, pero he elegido un delegado simple para el bien de este ejemplo

// Delegate to asynchronously invoke an action 
private delegate void AsyncActionExecution(); 

Lets ASUME que el método Invoke es el punto de entrada que creará todos los hilos y esperará su ejecución. Así que tenemos:

public void Invoke() 
{ 
    _TotalThreads = N; /* Change with the total number of threads expected */ 

    foreach (Object o in objects) 
    { 
     this.InvokeOneThread(); 
    }    

    // Wait until execution has been completed 
    _CompletedHandle.WaitOne(); 

    // Collect any exceptions thrown and bubble them up 
    foreach (WorkerThreadElement workerThreadElement in _WorkerThreadElements) 
    { 
     workerThreadElement.WorkerThread.EndInvoke(workerThreadElement.WorkerThreadResult); 
    } 
}   

InvokeOneThread es el método utilizado para crear un único hilo para una sola operación. Aquí tenemos que crear un elemento de hilo de trabajador e invocar el hilo real.

private void InvokeOneThread() 
{ 
    WorkerThreadElement threadElement = new WorkerThreadElement(); 
    threadElement.WorkerThread = new AsyncActionExecution(); 
    threadElement.WorkerThreadResult = threadElement.WorkerThread.BeginInvoke(actionParameters, InvokationCompleted, null); 

    _WorkerThreadElements.Add(threadElement); 
} 

de devolución de llamada de finalización hilo

private object _RowLocker = new object(); 

/// <summary> 
/// Increment the number of rows that have been fully processed 
/// </summary> 
/// <param name="ar"></param> 
private void InvokationCompleted(IAsyncResult ar) 
{ 
    lock (_RowLocker) 
    { 
     _RowsHandled++; 
    } 

    if (_TotalThreads == _ThreadsHandled) 
     _CompletedHandle.Set(); 
} 

Hecho

1

El uso de datos dinámicos puede pasar su objeto y el WaitHandle (ActionResetEvent) que le permite esperar a que todos los subprocesos de fondo para terminar sin declarar una clase extra:

static void Main(string[] args) 
{ 
    List<AutoResetEvent> areList = new List<AutoResetEvent>(); 
    foreach (MyObject o in ListOfMyObjects) 
    { 
     AutoResetEvent are = new AutoResetEvent(false); 
     areList.Add(are); 
     ThreadPool.QueueUserWorkItem(DoWork, new { o, are }); 
    }; 

    Console.WriteLine("Time: {0}", DateTime.Now); 
    WaitHandle.WaitAll(areList.ToArray()); 
    Console.WriteLine("Time: {0}", DateTime.Now); 
    Console.ReadKey(); 
} 

static void DoWork(object state) 
{ 
    dynamic o = state; 
    MyObject myObject = (MyObject)o.o; 
    AutoResetEvent are = (AutoResetEvent)o.are; 

    myObject.Execute(); 
    are.Set(); 
} 
Cuestiones relacionadas