Pregunta

Tengo el siguiente código que se produce una excepción:

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

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


Relacionado: en .Net ThreadPool Hilos

¿Fue útil?

Solución

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

Otros consejos

Puede añadir try / catch como esta:

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

Si está utilizando .Net 4.0, podría valer la pena investigar la clase Task , ya que puede hacerse cargo de esto para usted.

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

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

Para hacer frente a excepciones puede agregar una continuación de la tarea devuelta por StartNew. Se podría tener este aspecto:

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);

En el otro hilo, (en el método que está "haciendo cola", añada una cláusula intento de captura ... .A continuación, en la captura, coloque la excepción capturada en una variable compartida Excepción (visible para el hilo principal).

A continuación, en el hilo principal, cuando todos los artículos en cola han terminado (utilizar una matriz mango de espera para esto) Compruebe si algún hilo poblada esa excepción compartido con una excepción ... Si así fuera, volver a generar o manejarlo según corresponda. ..

aquí algunos ejemplos de código de un proyecto reciente he utilizado esto para ...
HasException es compartida booleano ...

    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 suelo hacer es crear un gran bloque try ... catch dentro del método action () a continuación, almacenar la excepción como una variable privada y luego manejarlo dentro del hilo principal

Código simple:

public class Test
{
    private AutoResetEvent _eventWaitThread = new AutoResetEvent(false);

    private void Job()
    {
        Action act = () =>
        {
            try
            {
                // do work...
            }
            finally
            {
                _eventWaitThread.Set();
            }
        };
        ThreadPool.QueueUserWorkItem(x => act());
        _eventWaitThread.WaitOne(10 * 1000 * 60);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top