[ Team LiB ] |
Recipe 15.5 Timing Out an Asynchronous DelegateProblemYou want an asynchronous delegate to operate only within an allowed time span. If it is not finished processing within this time frame, the operation will time out. If the asynchronous delegate times out, it must perform any cleanup before the thread it is running on is terminated. SolutionThe WaitHandle.WaitOne method can indicate when an asynchronous operation times out. The code on the invoking thread needs to periodically wake up to do some work along with timing-out after a specific period of time. Use the approach shown in the following code, which will wake up every 20 milliseconds to do some processing. This method also times out after a specific number of wait/process cycles (note that this code will actually time out after more than two seconds of operation since work is being done between the wait cycles): public class AsyncAction { public void TimeOutWakeAsyncDelegate( ) { AsyncInvoke method1 = new AsyncInvoke(TestAsyncInvoke.Method1); // Define the AsyncCallback delegate to catch EndInvoke if we timeout. AsyncCallback callBack = new AsyncCallback(TestAsyncInvoke.CallBack); // Set up the BeginInvoke method with the callback and delegate IAsyncResult asyncResult = method1.BeginInvoke(callBack,method1); int counter = 0; while (counter <= 25 && !asyncResult.AsyncWaitHandle.WaitOne(20, true)) { counter++; Console.WriteLine("Processing..."); } if (asyncResult.IsCompleted) { int retVal = method1.EndInvoke(asyncResult); Console.WriteLine("retVal (TimeOut): " + retVal); } else { Console.WriteLine("TimedOut"); } // Clean up asyncResult.AsyncWaitHandle.Close( ); } } The following code defines the AsyncInvoke delegate and the asynchronously invoked static method TestAsyncInvoke.Method1: public delegate int AsyncInvoke( ); public class TestAsyncInvoke { public static int Method1( ) { Console.WriteLine("Invoked Method1"); return (1); } public static void CallBack(IAsyncResult ar) { // Retrieve the delegate. AsyncInvoke ai = (AsyncInvoke) ar.AsyncState; // Call EndInvoke to retrieve the results. int retVal = ai.EndInvoke(ar); Console.WriteLine("retVal: " + retVal); } } DiscussionThe asynchronous delegates in this recipe are created and invoked in the same fashion as the asynchronous delegate in Recipe 15.4. However, instead of using the IsCompleted property to determine whether the asynchronous delegate is finished processing, WaitHandle.WaitOne is used. This method blocks the thread that it is called on either indefinitely or for a specified length of time. This method will stop blocking the thread when it is signaled by the ThreadPool that the thread has completed or timed out, and returns a true indicating that the asynchronous processing is finished and the calling thread has been signaled. If the processing is not finished before the allotted time-out value expires, WaitOne returns false. Note that the WaitOne method that accepts no parameters will block the calling thread indefinitely.
The TimeOutAsyncDelegate method in this recipe uses the WaitOne method to block the calling thread for two seconds. If the asynchronous delegate has not finished processing within this two-second period, the WaitOne method will return a false. If the asynchronous delegate finishes processing before the time-out value elapses, the calling thread is signaled by the running thread that the asynchronous delegate is finished and the WaitOne method stops blocking the calling thread and returns a value of true. If the WaitOne method returns true, the EndInvoke method should be called to retrieve any return values, ref parameter values, or out parameter values. The TimeOutWakeAsyncDelegate method in this recipe approaches the time-out technique a little differently than the first method. The TimeOutWakeAsyncDelegate method will periodically wake up (after 20 milliseconds) and perform some task on the calling thread; unlike the TimeOutAsyncDelegate method, which will continue blocking for the allotted time frame and not wake up. After 25 wait cycles, if the asynchronous delegate has not finished processing, the while loop will be exited, essentially timing out the delegate. If the delegate finishes processing before the 25 wait cycles have completed, the while loop is exited. The IsCompleted property is checked next to determine whether the asynchronous delegate has finished its processing at this time. If it has finished, the EndInvoke method is called to obtain any return value, ref parameter values, or out parameter values. Otherwise, the delegate has not completed within the allotted time span and the application should be informed that this thread has timed out. The call to the Close method of the WaitHandle object in effect performs the same function as a Dispose method. Any resources held by this instance of the WaitHandle object are released. See AlsoSee the "WaitOne Method" and "AsyncResult Class" topics in the MSDN documentation. |
[ Team LiB ] |