45 votes

Comment attraper les exceptions à partir d'un pool de threads.QueueUserWorkItem?

J'ai le code suivant qui lève une exception:

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

Lorsque l'action déclenche une exception, mon programme se bloque. Quelle est la meilleure pratique pour gérer cette situation?


Connexes: les Exceptions sur .Net Pool De Threads Les Threads

72voto

Prankster Points 1810

Vous pouvez ajouter des try/catch comme ceci:

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

25voto

Tormod Fjeldskår Points 4023

Si vous avez accès à l' actioncode source, insérez un bloc try/catch dans la méthode; sinon, créez un nouveau tryAction méthode qui encapsule l'appel à l' action dans un bloc try/catch.

19voto

Samuel Jack Points 14556

Si vous êtes en utilisant .Net 4.0, il pourrait être intéressant d'enquêter sur la Tâche de la classe, car il peut prendre soin de cela pour vous.

L'équivalent de votre code d'origine, mais à l'aide de Tâches, ressemble à

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

Pour gérer les exceptions, vous pouvez ajouter une continuation de la Tâche retourné par StartNew. Il pourrait ressembler à ceci:

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

3voto

Charles Bretana Points 59899

Sur l'autre fil, (dans la méthode que vous sont des "files d'attente", ajoutez un try catch clause... .Puis dans la prise, place de l'exception interceptée dans un partagées Exception de la variable (visible par le thread principal).

Puis dans votre thread principal, lorsque tous en file d'attente les éléments ont fini (utiliser une attente poignée de tableau pour cette) Vérifier si certains thread peuplées qui ont partagé l'exception une exception... Si il l'a fait, renvoyer ou de le gérer comme il se doit...

voici un exemple de code à partir d'un projet récent, j'ai utilisé ce pour...
HasException est partagé boolean...

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

1voto

oscarkuo Points 5849

Ce que je fais habituellement est de créer un gros bloc try ... catch à l'intérieur de la méthode d'action() ensuite stocker l'exception comme une variable privée puis la poignée dans le thread principal

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X