waitcallback thread practices example ejemplo best c# .net multithreading threadpool

c# - practices - ¿Cómo capturar excepciones de un ThreadPool.QueueUserWorkItem?



threadpool.queueuserworkitem example c# (5)

Tengo el siguiente código que lanza una excepción:

ThreadPool.QueueUserWorkItem(state => action());

Cuando la acción lanza una excepción, mi programa falla. ¿Cuál es la mejor práctica para manejar esta situación?

Relacionados: Excepciones en .Net ThreadPool Threads


En el otro hilo, (en el método en el que está "haciendo cola", agregue una cláusula try catch .... Luego, en el retén, coloque la excepción capturada en una variable de excepción compartida (visible en el hilo principal).

Luego, en su subproceso principal, cuando todos los elementos en cola hayan finalizado (use una matriz de manejadores de espera para esto) Verifique si algún subproceso completó esa excepción compartida con una excepción ... Si lo hizo, vuélvalo a un lado o manéjelo como corresponda ...

Aquí hay algunos ejemplos de código de un proyecto reciente para el que utilicé ...
HasException es booleano compartido ...

private void CompleteAndQueuePayLoads( IEnumerable<UsagePayload> payLoads, string processId) { List<WaitHandle> waitHndls = new List<WaitHandle>(); int defaultMaxwrkrThreads, defaultmaxIOThreads; ThreadPool.GetMaxThreads(out defaultMaxwrkrThreads, out defaultmaxIOThreads); ThreadPool.SetMaxThreads( MDMImportConfig.MAXCONCURRENTIEEUSAGEREQUESTS, defaultmaxIOThreads); int qryNo = 0; foreach (UsagePayload uPL in payLoads) { ManualResetEvent txEvnt = new ManualResetEvent(false); UsagePayload uPL1 = uPL; int qryNo1 = ++qryNo; ThreadPool.QueueUserWorkItem( delegate { try { Thread.CurrentThread.Name = processId + "." + qryNo1; if (!HasException && !uPL1.IsComplete) IEEDAL.GetPayloadReadings(uPL1, processId, qryNo1); if (!HasException) UsageCache.PersistPayload(uPL1); if (!HasException) SavePayLoadToProcessQueueFolder( uPL1, processId, qryNo1); } catch (MeterUsageImportException iX) { log.Write(log.Level.Error, "Delegate failed " iX.Message, iX); lock (locker) { HasException = true; X = iX; foreach (ManualResetEvent txEvt in waitHndls) txEvt.Set(); } } finally { lock(locker) txEvnt.Set(); } }); waitHndls.Add(txEvnt); } util.WaitAll(waitHndls.ToArray()); ThreadPool.SetMaxThreads(defaultMaxwrkrThreads, defaultmaxIOThreads); lock (locker) if (X != null) throw X; }


Lo que normalmente hago es crear un bloque grande try ... catch dentro del método action () luego almacenar la excepción como una variable privada y luego manejarla dentro del hilo principal


Puedes agregar try / catch de esta manera:

ThreadPool.QueueUserWorkItem(state => { try { action(); } catch (Exception ex) { OnException(ex); } });


Si está utilizando .Net 4.0, podría valer la pena investigar la clase de Task porque puede encargarse de esto por usted.

El equivalente de su código original, pero usando Tareas, parece que

Task.Factory.StartNew(state => action(), state);

Para lidiar con las excepciones, puede agregar una continuación a la tarea devuelta por StartNew. Podría verse así:

var task = Task.Factory.StartNew(state => action(), state); task.ContinueWith(t => { var exception = t.Exception.InnerException; // handle the exception here // (note that we access InnerException, because tasks always wrap // exceptions in an AggregateException) }, TaskContinuationOptions.OnlyOnFaulted);


Si tiene acceso al código fuente de la action , inserte un bloque try / catch en ese método; de lo contrario, cree un nuevo método tryAction que tryAction la llamada a la action en un bloque try / catch.