Domanda

Ho il seguente codice che genera un'eccezione:

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

Quando l'azione genera un'eccezione, il mio programma si blocca. Qual è la migliore pratica per la gestione di questa situazione?


Related: su .Net ThreadPool discussioni

È stato utile?

Soluzione

Se si ha accesso al codice sorgente di action, inserire un blocco try / catch in quel metodo; in caso contrario, creare un nuovo metodo tryAction che avvolge la chiamata a action in un blocco try / catch.

Altri suggerimenti

È possibile aggiungere try / catch in questo modo:

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

Se si utilizza Net 4.0, potrebbe essere la pena di indagare il Task classe perché si può prendere cura di questo per voi.

L'equivalente del codice originale, ma usando le attività, si presenta come

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

Per far fronte a eccezioni è possibile aggiungere una continuazione alla Task restituito da StartNew. Potrebbe assomigliare a questo:

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

D'altro thread, (nel metodo che si sta "Queuing", aggiungere una clausola try cattura ... .Poi nella cattura, posizionare l'eccezione catturato in una variabile di eccezione condiviso (visibile al thread principale).

Poi, nel tuo thread principale, quando tutti gli elementi in coda hanno finito (utilizzare un array maniglia attesa per questo) Controllare se qualche filo popolato tale eccezione in comune con un'eccezione ... Se così fosse, rigenerare o gestirlo in modo appropriato. ..

Ecco alcuni esempi di codice da un recente progetto che ho usato questo per ...
HasException è booleano condiviso ...

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

Cosa faccio di solito è quello di creare un grande blocco try ... catch dentro l'azione () metodo quindi memorizzare l'eccezione come una variabile privata quindi gestire all'interno del thread principale

Codice Semplice:

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);
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top