views:

685

answers:

1

I want to have an exception handling approach in my Asynchronous programming (beginInvoke/endInvoke) wherein if any one of the thread(beginInvoke) fails, then I want all other asynchrounous processing thread to stop working. Please suggest some solution?, below I am attaching my sample code also:

public List<ThreadResultDto> SendMailAsynch(List<ThreadRequestDto>  requestDto)
{
    List<ThreadResultDto> resultDto = new List<ThreadResultDto>();
    List<IAsyncResult> asyncResults = new List<IAsyncResult>();

    foreach (ThreadRequestDto t in requestDto)
    {
        //Create a delegate.
        DoSomeAsynchWorkDelegate del = new DoSomeAsynchWorkDelegate(DoSomeAsynchWork);
        // Initiate the asynchronous call
        IAsyncResult a = del.BeginInvoke(t,null, del);
        //IAsyncResult a = del.BeginInvoke(t, null,null);
        asyncResults.Add(a);
    }

    foreach (IAsyncResult ar in asyncResults)
    {
        // wait for each one to complete, then call EndInvoke, passing in the IAsyncResult.
        // We cast ar.AsyncState to a DoSomeAsynchWorkDelegate, as we passed it in as the second parameter to BeginInvoke. 
        ar.AsyncWaitHandle.WaitOne();

        //AsyncState property of IAsyncResult is used to get the delegate that was used to call that method
        DoSomeAsynchWorkDelegate del = (DoSomeAsynchWorkDelegate)ar.AsyncState;

        // Call EndInvoke to get the result.  Add the result to the list of items. 
        resultDto.Add(del.EndInvoke(ar));
    }

    return resultDto;
}
+1  A: 

The best way is probably to use a shared ManualResetEvent.

For example:

class MyClass
{
    private ManualResetEvent workFailedEvent = new ManualResetEvent(false);

    public List<ThreadResultDto> SendMailAsynch(List<ThreadRequestDto>  requestDto)
    {
        workFailedEvent.Reset();

        // --- The rest of your code as written in your post ---
    }

    private void DoAsyncWorkFirst()
    {
        try
        {
            for (int i = 0; i < 10000; i++)
            {
                if (workFailedEvent.WaitOne(0, true))
                {
                    break;
                }

                // -- Do some work here ---
            }
        }
        catch (MyException)
        {
            workFailedEvent.Set();
        }
    }

    private void DoAsyncWorkSecond()
    {
        try
        {
            for (int j = 0; j < 20000; j++)
            {
                if (workFailedEvent.WaitOne(0, true))
                {
                    break;
                }
                // --- Do some different work here ---
            }
        }
        catch (MyOtherException)
        {
            workFailedEvent.Set();
        }
    }
}

The interesting part here is the call to WaitOne(0, true). If you use a timeout of 0 then the thread will not block. Since the ManualResetEvent is synchronized by the OS, this particular method call is a convenient way to check for a signal without having to worry about race conditions or implement your own locking.

Aaronaught
Won't a volatile bool also work as a termination flag?
Amnon
In theory yes. In some cases, it might even be faster. But the *volatile* keyword has a lot of side effects - it actually changes the way code is generated for every block that accesses the variable, not just the variable itself. I generally prefer locks and synchro primitives to *volatile* fields unless performance is a major issue.
Aaronaught