Posted by: Cirilo Meggiolaro | 12/19/2008

Tip of the day #66 – Using signals to execute threads

Before we start let’s rewind a little bit and check what I’ve written about ThreadPool and thread calls:

Tip #43 explained how to enqueue calls to the ThreadPool;

Tip #49 described how to execute methods based on time.

Today’s tip describes how to execute a method based on signals using the ThreadPool class functionalities.

For this example we are going to use the static RegisterWaitForSingleObject method available under the ThreadPool class that allow us to define timeouts to signal a callback to execute or signal manually with the use of a AutoResetEvent object. The following overloads are available:

  • public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, int millisecondsTimeOutInterval, bool executeOnlyOnce);
  • public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce);
  • public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, TimeSpan timeout, bool executeOnlyOnce);
  • public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, uint millisecondsTimeOutInterval, bool executeOnlyOnce);

Parameters

  • waitObject: For this example we are going to use an instance of a AutoResetEvent class to set manual signals that I am going to explain later on;
  • callBack: A WaitOrTimerCallback delegate. The method must match the WaitOrTimerCallback signature;
  • state: You may want to pass a parameter to the callback method. The state object may be used for this purpose. If you don’t want to pass any parameter to the callback method, pass null;
  • timeout: Defines if the callback is signaled based on time. Defining the value as Timeout.Infinite makes the method not be signaled based on time;
  • executeOnlyOnce: A Boolean flag indicating if the method will be called just once when either a timeout is defined or when using AutoResetEvent signals.

AutoResetEvent

One of the objects that we need for our example is the AutoResetEvent class that provides a way to notify a thread that an event has occurred. This class may be used to allow communication between threads. In a general way this is how it works:

  • A thread invokes the WaitOne method from the AutoResetEvent class what makes the thread to keep blocked;
  • When the AutoResetEvent Set method is invoked, the waiting thread is released and the thread resumes its execution;
  • The AutoResetEvent remains in a signaled state until the waiting thread has been released. Once there is no thread to be released anymore, the AutoResetEvent changes its state to non-signaled.

How to…

1. Creates a RegisteredWaitHandleObject;

RegisteredWaitHandle waitHandle = null;

2. Declares and instantiate a AutoResetEvent responsible for signal the waiting object;

AutoResetEvent resetEvent = new AutoResetEvent(false);

3. Registers the delegate to run based on signals.
waitHandle = ThreadPool.RegisterWaitForSingleObject(resetEvent, new WaitOrTimerCallback(MyCallBackMethod), null, Timeout.Infinite, false);

4. When necessary, invoke the Set method to signal the waiting object manually;

resetEvent.Set();

5. If just one callback execution must run, unregister the delegate;

waitHandle.Unregister(null);

The final code must be similar to the following:

class Program
{
    /// Declares the RegisteredWaitHandle object
    private static RegisteredWaitHandle waitHandle = null;

    static void Main(string[] args)
    {
        /// Used to signal the registered wait handle object.
        AutoResetEvent resetEvent = new AutoResetEvent(false);

        /// Registers a delegate to run based on signals.
        waitHandle = ThreadPool.RegisterWaitForSingleObject(resetEvent, new WaitOrTimerCallback(MyCallBackMethod), null, Timeout.Infinite, false);

        /// Pauses the thread to simulate some task being performed.
        Thread.Sleep(3000);

        /// Manually signals the waithandle object.
        resetEvent.Set();

        /// Pauses the thread to allow the callback to run.
        Thread.Sleep(100);

        Console.Read();
    }

    private static void MyCallBackMethod(object state, bool timedOut)
    {
        if (!timedOut)
        {
            Console.WriteLine(“Callback method has been signaled manually by AutoResetEvent.”);

            /// Unregisters the delegate to avoid future execution
            if (waitHandle != null) waitHandle.Unregister(null);
        }
        else
        {
            Console.WriteLine(“Callback method has been signaled by timeout.”);
        }
    }
}


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: