Исключения в потоках .Net ThreadPool - PullRequest
4 голосов
/ 21 марта 2009

Дубликат: Как перехватить исключения из ThreadPool.QueueUserWorkItem?


Я ставлю в очередь несколько делегатов в .Net ThreadPool для большого количества независимых удаленных вызовов, которые сами вызывают несколько баз данных и других автономных ресурсов. Ставя в очередь эти вызовы в ThreadPool, я могу выполнять их одновременно и минимизировать общую задержку.

private void CompleteAndQueuePayLoads(IEnumerable<UsagePayload> payLoads)
{
    List<WaitHandle> waitHndls = new List<WaitHandle>();
    foreach (UsagePayload uPyLd in payLoads)
    {
        ManualResetEvent txEvnt = new ManualResetEvent(false);
        UsagePayload uPyLd1 = uPyLd ;
        ThreadPool.QueueUserWorkItem(
            delegate
                {
                    if (!uPyLd1 .IsComplete)
                        // IEEDAL.GetPayloadReadings is long running DB call
                        try { IEEDAL.GetPayloadReadings(uPyLd1 ); }
                        catch (IEEAccessException iX)
                        {
                            log.Write(log.Level.Error,
                                  "IEEWSDAL.CompleteAndQueuePayLoads " + 
                                   " Delegate Failed " +
                                  iX.Message, iX);
                            txEvnt.Set();
                            throw;  // this causes parent thread to crash!
                            // was going to try Thread.Abort next ...
                            // Thread.CurrentThread.Abort();
                        }
                    UsageCache.PersistPayload(uPyLd1 );
                    SavePayLoadToProcessQueueFolder(uPyLd1 );
                    txEvnt.Set();
                });
        waitHndls.Add(txEvnt);
    }
    util.WaitAll(waitHndls.ToArray()); //To waitone on > 64 waithandles
}

Но весь пакет должен обрабатываться транзакционно, т. Е. Вывод родительского потока должен выполняться только в том случае, если все дочерние потоки были успешными. Я закодировал дочерний поток, чтобы он выдавал пользовательское исключение, когда оно не удавалось, но я обнаружил, что это вызывает сбой родительского потока, так как эти исключения не могут быть «перехвачены» в родительском потоке ...

Я читал о выбросе UnHandledExceptionEvent CLR, когда это происходит, но мне нужно «обработать» это исключение в методе, в котором эти дочерние потоки помещаются в очередь и порождаются, чтобы управлять немедленной последующей обработкой на основе успеха триада ребенка ... Как мне это сделать?

Ответы [ 3 ]

3 голосов
/ 21 марта 2009

Если поток завершается с ошибкой, вы можете отметить, что по крайней мере один сбой произошел внутри локальной переменной функции CompleteAndQueuePayLoads, и добавить переменную исключений / сбоев для последующего изучения.

2 голосов
/ 21 марта 2009

Я делаю это много в моем текущем проекте. Подход, который я выбрал, состоял в том, чтобы создать свой собственный планировщик, который будет принимать делегата, добавлять его в мою очередь и запускать их для обработки синхронизации в конце и т. Д.

«Уловка», которую я использовал в этом случае, заключается в том, чтобы не вызывать делегат непосредственно в пуле потоков, а скорее вызывать метод в моем планировщике, который обертывает делегат и обрабатывает исключение более изящно. Таким образом, фактический внутренний вызов метода всегда обрабатывается соответствующим (для меня) образом.

Когда происходит исключение, мой планировщик уведомляется и прекращает планирование будущих задач (что является хорошим бонусом), но также заботится о том, чтобы сообщить вызывающему абоненту, что было единственное исключение.

1 голос
/ 29 октября 2009

Вы можете посмотреть расширения библиотеки Parallel для 3.5. Вы можете использовать Parallel.Invoke в своем блоке кода, чтобы делать именно то, что вы пытаетесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...