Below is a class having the method 'SomeMethod' that illustrates my problem.
class SomeClass
{
AutoResetEvent theEvent = new AutoResetEvent(false);
// more member declarations
public void SomeMethod()
{
// some code
theEvent.WaitOne();
// more code
}
}
The method is designed to be thread-safe and will be called in different threads. Now my question is how is it possible to unblock all threads that have called the 'WaitOne' method on the 'theEvent' object at any point of time? This requirement frequently arises in my design because I need to be able to gracefully stop and start my multi-threaded program. It seems to me that it's fairly simple to start a multi-threaded program, but tricky to stop one.
Here's what I have tried so far which apparently works. But is this the standard approach?
public void UnblockAll()
{
do
{
theEvent.Set();
} while (theEvent.WaitOne(0));
}
The 'UnblockAll' method is a member of the 'SomeClass' class. The technique used here is based on the MSDN documentation of the WaitOne method. I am quoting the relevant part of the documentation below:
If millisecondsTimeout is zero, the method does not block. It tests the state of the wait handle and returns immediately.
In the do..while loop, I call the Set method. This releases a single thread that may have blocked due to a call to the WaitOne method (coded inside the 'SomeMethod' method). Next I test the state of the 'theEvent' object just to know whether it's signalled. This test is done by calling the overloaded version of the WaitOne method that takes a time out parameter. The argument which I use when I call the WaitOne method is zero, which as per the documentation results in the call returning immediately with a boolean value. If the return value is true, then the 'theEvent' object was in a signalled state. If there was at least a single thread blocked on the call to the 'WaitOne' method in the 'SomeMethod' method, the call to the 'Set' method (coded inside the 'UnblockAll' method) would unblock it. Consequently the call to the 'WaitOne' method at the end of the do..while statement in the 'UnblockAll' method would return false. The return value is true only if there were no threads blocked.
Is the above reasoning right and if it's right, is the technique a standard way to deal with my problem? I am trying to use the solution primarily on the .net compact-framework 2.0 platform.
You have three viable options. Each one has its own advantages and disadvantages. Pick the one that works best for your specific situation.
Option 1 - Poll the WaitHandle
.
Instead of doing an indefinite blocking call use one with a timeout and reinstate the block if a shutdown request has not been given.
public void SomeMethod()
{
while (!yourEvent.WaitOne(POLLING_INTERVAL))
{
if (IsShutdownRequested())
{
// Add code to end gracefully here.
}
}
// Your event was signaled so now we can proceed.
}
Option 2 - Use a separate WaitHandle
for requesting shutdown
public void SomeMethod()
{
WaitHandle[] handles = new WaitHandle[] { yourEvent, shutdownEvent };
if (WaitHandle.WaitAny(handles) == 1)
{
// Add code to end gracefully here.
}
// Your event was signaled so now we can proceed.
}
Option 3 - Use Thread.Interrupt
Do not confuse this with Thread.Abort
. Aborting a thread is definitely unsafe, but interrupting a thread is completely different. Thread.Interrupt
will "poke" the builtin blocking calls used in the BCL including Thread.Join
, WaitHandle.WaitOne
, Thread.Sleep
, etc.