views:

956

answers:

3

Duplicate: How to catch exceptions from a ThreadPool.QueueUserWorkItem?


I am queueing up multiple delegates on the .Net ThreadPool for a large number of independant remoting calls that themselves call multiple databases and other offline resources. By Queueing these calls on the ThreadPool I can run them concurrently and minimize the overall latency.

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
}

But the entire batch needs to be handled transactionally, I.E., the output of the Parent Thread needs to only be allowed to proceed if all child threads were successful. I had coded the child thread to throw a custom exception when it failed, but I have discovered that this causes the parent thread to crash, as these exceptions cannot be "caught" in the parent thread...

I have read about the UnHandledExceptionEvent throw by the CLR when this happens, but I need to "handle" this exception in the method where these child threads are being Queued up and spawned, to control the immediate downstream processing based on the success of teh child threeads... How do I go about this?

+3  A: 

If the thread fails, you could mark that at least one failure has occured inside a local variable of the CompleteAndQueuePayLoads function, and add exception/failures variable to be examined later.

simonjpascoe
+1  A: 

I do this a lot in my current project. The approach I took was to make my own scheduler that takes the delegate, adds it to my own queue, and runs them to handle the synchronization at the end, etc.

The "trick" I've used in this case is to not call the delegate directly on the thread pool, but rather call a method in my scheduler that wraps the delegate and handles the exception more gracefully. This way, the actual, internal method call is always handled in an appropriate (for me) manner.

When an exception happens, my scheduler is notified and stops scheduling future tasks (which is a nice bonus), but also takes care of telling the caller that there was a single exception.

Reed Copsey
+1  A: 

You might look into the Parallel library extensions for 3.5. You can use Parallel.Invoke on your code block to do exactly what you are attempting.

Thomas
Yes I just saw that recently, but I have solved this issue using an array of waithandles, with method that iterates through the array looking to see that all of them have been released..
Charles Bretana