Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I unblock threads which have called the WaitOne method on an AutoResetEvent object?

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.

like image 456
ghd Avatar asked May 09 '11 16:05

ghd


1 Answers

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.

like image 113
Brian Gideon Avatar answered Sep 25 '22 19:09

Brian Gideon