RSS

Win32 Events


Win32 Events

I have some code that runs in a background thread within my application. What is a good way for it to indicate it is done or has reached an error condition?

Communication between threads within an application can be a tricky affair if you haven’t worked with threaded code very much. A simple (and problematic) approach would be to pass through a pointer to a callback function to the background thread when it is started. When the code finishes processing (or hits an error condition) it calls the function pointer and exits.

Several issues arise from this approach:

  • Is this code in the function threadsafe itself? Even though the function logically resides in the main thread, the code will be executed in the context of the background thread. Accessing/updating variables, and so on, within the function could cause data/memory corruption if multiple threads update that data at the same time. These can also be very thorny to find and fix since they involve the timing of the calls and the specific ways the data is corrupted.
  • The background code is unable to exit until the function returns. This could be very bad if the function performs a lengthy operation. It could have the net effect (if poorly done) to never terminate the background task until the application exits.
  • The main thread would have to periodically check to see if the background thread is finished by accessing state owned (or managed) by the callback function. This can make a multithreaded application inefficient as the main thread has to spend time checking to see if the background thread is done. It gets worse (and more complex) if there are multiple background threads.

Ideally, you'd like to have the operating system manage some of this communication. This would involve a safe and reliable means for a thread to notify one or more other threads of some event or state change within the background task. Fortunately, Windows provides something called "Win32 Events that is exactly what we need.

A Win32 event is a system object that provides for interthread communication (including interprocess) via a signaling metaphor which supports two states- signaled and nonsignaled. A signaled state means the event is "active or "on and is used by waiting threads to know that they may proceed. A nonsignaled state means the event is "not active or "off and indicates to waiting threads that they must continue to wait.

There are two types of events: manual-reset and auto-reset. A manual-reset event means that an explicit call to the Win32 API ResetEvent() must be made to move the event from the signaled to nonsignaled state. A call to the Win32 API SetEvent() is made to move from the nonsignaled state to signaled state. An auto-reset event moves from the signaled to nonsignaled state automatically without a call to ResetEvent(). However, a call to SetEvent() must still be made to move to the signaled state.

You might be wondering when you'd use a manual-reset event versus an auto-reset event. It really comes down to convenience for the programmer. An auto-reset event is useful when you have a primary thread that needs to communicate with a series of worker threads and wants one worker thread to proceed per signal. A thread-pooling feature where worker threads are created and then suspend awaiting something to do is an example. The main thread "wakes up a thread (in this case, it doesn't care which one) via the auto-reset event. Windows takes care of allowing one and only one thread to proceed (or more accurately "to be signaled) while the others are blocked. After the thread proceeds (or is unblocked), the event moves to the nonsignaled state and the other threads continue to be blocked. A manual-reset event is more flexible in that the programmer has total control over when an event moves from state-to-state. If there are multiple threads blocked awaiting a signal, and the event is set to the signaled state, all threads are unblocked, not just one.

To create a Win32 event, you would write some code like this:

	HANDLE evt = 
CreateEvent(NULL,  // ptr to SECURITY_ATTRIBUTES; usually NULL
	         TRUE,  // TRUE=manual, FALSE=auto
	         FALSE,  // signaled state
	         "MyCoolEvent   // name of event; optional
	       );
		   

What we've done here is create a manual-reset event initialized to the nonsignaled state. This is a very common way to create an event before you use it. You might do this in a constructor or other initialization sequence of a body of code, for example.

Next, we assume we have some code that runs in a worker thread that needs to know when the event is moved to a signaled state.

Here is how the worker thread would await being signaled:

	HANDLE evt = OpenEvent( EVENT_ALL_ACCESS,  // security access request
				 	TRUE,  // is handle inheritable by other processes
					"MyCoolEvent  // name of event
 );

	DWORD dwResult = WaitForSingleObject(  
				 evt,   // handle
				 INFINITE // timeout; milliseconds or INFINITE
			          );

	if ( dwResult == WAIT_OBJECT_0 )
	{
		// signaled..
	}

Looking at this code, you'll notice that we request the event by its name. This assumes that the background thread knows what special name to ask for but it is a nice way to get access to the event handle without passing it through to the thread directly. The WaitForSingleObject() function has a series of sibling functions such as WaitForMultipleObjects(), MsgWaitForMultipleObjects(), and the like. Each is a variant on the idea of waiting for an event (or other synchronization artifact) to be signaled. The MsgWait... variants have a useful property in that they will signal when the event is signaled or a Windows message enters the queue. This can be really handy if you have a background thread that displays a user interface that needs to be updated and respond to user actions while waiting for an event signal.

Finally, the main thread code that created the event needs to signal the waiting threads when it is okay for them to proceed. It does so like the following:

	SetEvent( evt );

This moves the event from the nonsignaled to signaled state. If the event is already signaled, it has no effect. When done with the event object completely, a call is made to the Win32 API CloseHandle() to release it.

As you can see, Win32 events are nifty items to include in your programmer bag-of-tricks. They can easily, safely, and efficiently solve basic notification needs between threads or processes without a lot of code. There are many other synchronization objects in Windows such as mutexes, critical sections, and so on. In future newsletters, we'll take a look at these and see how they can help solve other threading/data access issues.


Mark M. Baker is the Chief of Research & Development at BNA Software located in Washington, D.C. He can be contacted at mark_baker@mindspring.com.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Best of the Web

First C Compiler Now on Github

The earliest known C compiler by the legendary Dennis Ritchie has been published on the repository.

Quick Read

HTML5 Mobile Development: Seven Good Ideas (and Three Bad Ones)

HTML5 Mobile Development: Seven Good Ideas (and Three Bad Ones)

Quick Read

Building Bare Metal ARM Systems with GNU

All you need to know to get up and running... and programming on ARM

Quick Read

Amazon's Vogels Challenges IT: Rethink App Dev

Amazon Web Services CTO says promised land of cloud computing requires a new generation of applications that follow different principles.

Quick Read

How to Select a PaaS Partner

Eventually, the vast majority of Web applications will run on a platform-as-a-service, or PaaS, vendor's infrastructure. To help sort out the options, we sent out a matrix with more than 70 decision points to a variety of PaaS providers.

Quick Read


More "Best of the Web" >>

Video