In the MSDN forums for Smart Device development, I have come across a few requests for guidance for which native synchronization objects would be part of the solution. Having encountered the questions on more than one occasion, I've written this introduction to Native Events on Windows Mobile devices. This paper is specifically written for managed code developers, though a native code developer should not experience challenges in interpreting the code examples in this article.
What is a Synchronization Object and Why do I Need Them?
Synchronization objects are used to coordinate operations being performed by more than one thread. In their simplest form, a synchronization object would be used to ensure that multiple threads are not altering the same object simultaneously, though they can also be used to facilitate communication among programs. The .NET Compact Framework contains a number of managed classes that can be used for thread level synchronization, these classes can be found in the
These classes work within the context of the same process, and are for coordinating the actions of threads within that process. Most of the Operating System supplied functionality that I discuss here works across process boundaries. I won't be discussing the managed synchronization classes here, only the native synchronization functions. At the time of this writing, the Operating System supplied synchronization objects are not directly supported by the .NET framework, so we will need to use P/Invoke to access them. I will be covering the following objects:
|Used to send signals to threads to continue execution|
|Limits the number of threads that can access a resource|
|Used to ensure that only one thread is accessing a resource at a time|
I've wrapped the native function calls for the native synchronization objects into separate classes. The abstract class
SyncBase contains the functionality that is common to all three of the synchronization objects defined here. Each one of the three synchronization classes derives from this abstract class. Take note that these classes implement
IDisposable. These classes hold onto Windows handles (which are system resources), and these handles should not be held longer than necessary.
While you are free to use this code as you like, I would highly encourage you to study the documentation in MSDN for the synchronization functions. My use of the available functions is non-exhaustive, and targets what I think to be the most commonly used functionality. So, there are other capabilities that the synchronization functions have that I do not mention here.
Events are the simplest of the synchronization objects. They are like traffic signals; code that waits on an event will halt until the event changes to a signaled state. An event can optionally have a name. An event with a name can be shared among several processes. Since there is no native support in the .NET Framework for system events, we will need to use P/Invoke to interact with them. The
CreateEvent function is used to create events, and it is defined in CoreDLL. An event can be a manual reset event or an auto-reset event. For a manual reset event, once the event is set to a signaled state, it will remain in that state until it is explicitly changed to a non-signaled state using the
ResetEvent function. While the event is in a signaled state, every thread that attempts to wait on the event will continue to run without being blocked. For an auto-reset, once an event is set to signaled state, it will remain in that state until a thread waits on it. Once a thread waits, it will be allowed to continue, and the event will be automatically reset back to a non-signaled state. For momentarily setting an event to a signaled state, there is a function named
PulseEvent. The behaviour of
PulseEvent is dependent on whether it is being used against a manual reset or auto-reset event. When called against a manual reset event, all threads which can currently be unblocked are unblocked, and the event changes back to a non-signaled state. For auto-reset events, a single thread is released from being blocked, and the event then returns to a non-signaled state.
The calling signature for
CreateEvent is defined in the C++ header as follows:
|This should always be |
|Controls whether a manual reset or auto-reset event is created.|
|Specifies whether or not the event will be in a signaled state when it is created.|
|The name of the event to create. If no name is specified, then an unnamed event is created, and the event will only have meaning within the process in which it was created.|
Calling it will require the use of a P/Invoke:
public static extern IntPtr CreateEvent(
[In, MarshalAs(UnmanagedType.Bool)] bool ManualReset,
[In, MarshalAs(UnmanagedType.Bool)] bool bInitialState,
[In, MarshalAs(UnmanagedType.BStr)] string Name
If you attempt to make the appropriate P/Invoke statements for
ResetEvent, they will all fail. They fail because none of these functions exist in any Windows Mobile DLL. If you look in the C++ header file named "kfuncs.h", you will see that these functions are defined as inline calls to
EventModify. The first parameter in the call to
EventModify is the handle to the event that we are using, and the second parameter is a numeric value that indicates what is to be done with the event. In my code, I made a P/Invoke statement for
EventModify, and declared appropriate calls to it for
You almost have enough information to begin using events. The one last missing piece is what you must do with an event handle when you are no longer using it. When you no longer need an event, release it by calling
CloseHandle. Now, on to our first code example. I've already declared the P/Invoke statements that we will be using to access the functions mentioned above, in a single project called NativeSync. If you open CoreDLL.cs, you will find P/Invokes for
CloseHandle. I've also created a class named
SystemEvent to package the event related functions. The class implements
IDisposable so that the handle can be released when the event is no longer being used.
The first code example is in a project named "SoundOnEvent". The program has two threads. In addition to the GUI thread, there is a thread with an entry point in the method
SoundLoop whose definition is given below.
SoundLoop will wait on an event and play a sound when the event is signaled. The form in which this program is hosted only has a single button. The event handler for that button calls
SetEvent on another event object. Note that the instance of the
Event object being used by the button's event handler is different than the instance in the
SoundLoop method. Since both instances were created with the same name, the Operating System will give both of these object instances the same kernel object.
private void Form1_Load(object sender, EventArgs e)
_soundEvent = new SystemEvent("PlaySound", false, false);
Thread t = new Thread(new ThreadStart(SoundLoop));
using (SystemEvent evt = new SystemEvent("PlaySound", false, false))
private void cmdCreateEvent_Click(object sender, EventArgs e)
Source code from program SoundOnEvent
while loop looks notoriously similar to an antipattern that is frequently discouraged, known as a busy spin or spinning on a variable. Although the code looks like a busy spin, it is not; in a busy spin, a code block is unnecessarily repeated, performing no real work while burning CPU cycles. In the above code, the thread completely halts until it is time to do work, and doesn't waste CPU cycles.
While a handle to one event can't be directly passed to another process (a handle only has meaning within the context of a specific process), if another process attempts to make an event with the same name, it will receive its own handle to the already existing object. If we had another program that called
SetEvent for this same event, this first program would react to it ( no code modifications needed!).
public partial class Form1 : Form
SystemEvent _soundEvent = new SystemEvent("PlaySound", false, false);
private void cmdCreateEvent_Click(object sender, EventArgs e)
private void miExit_Click(object sender, EventArgs e)
private void Form1_Closing(object sender, CancelEventArgs e)
Source code for SoundOnEventTrigger, which sends events to SoundOnEvent
Waiting on Multiple Objects
When you have a collection of objects and would like to wait for any one of them to be signaled, the method
WaitForMultipleObjects can be used. On the desktop version of Windows, this function can be used to wait for all events to be signaled, or wait for any one of them to be signaled. For the Windows CE Operating System, this function can only be used to wait on one of any events to occur. The native prototype for the function is as follows:
DWORD WINAPI WaitForMultipleObjects(
__in DWORD nCount,
__in const HANDLE *lpHandles,
__in BOOL bWaitAll,
__in DWORD dwMilliseconds
The first parameter is the number of synchronization objects being passed, and the second parameter is an array of object handles. The third parameter must always be
false (on the desktop OS, if the third parameter were
true, then the method would wait on all of the objects to be signaled). The last parameter will be the number of milliseconds to wait for one of the objects to be signaled, or -1 for no timeout. In my code, I have simplified the calling signature to only take a timeout value and the list of synchronization objects on which to wait. The method is implemented on the
SyncBase class, since the system event is not the only type of object on which a program can wait (we will cover the other types of objects shortly).
The example code demonstrating
WaitForMultipleObjects is similar to the first example. For my wrapper to the
WaitOnMultipleObjects function, I've had the method return a reference to the object that was signaled and caused the thread to be unblocked. The example program will use information on which event was signaled to decide which sound to play. A user can signal one of the three system event objects through three buttons on the interface. There is also a fourth event which is not accessible through a button on this program's UI. The fourth event has the same name as the event used on the first example program, so the
SoundOnEventTrigger can be used to trigger the fourth event.
using (SystemEvent evt =
new SystemEvent("PlaySound", false, false))
SystemEvent signaledEvent = SyncBase.WaitForMultipleObjects(
) as SystemEvent;
target = 4;
if (signaledEvent == _event1)
target = 1;
if (signaledEvent == _event2)
target = 2;
if (signaledEvent == _event3)
target = 3;
SndPlaySync(String.Format(SoundPath, target), 0);
Once you understand how to use the event object, you have a foundation for using mutexes and semaphores; they both extend on the concept of the event.
A mutex is used to ensure that only one thread has access to a resource. A mutex is in a signaled state until a thread waits on it. When a thread waits on a mutex and if no other threads are waiting on the mutex, then it is granted ownership of the mutex, its wait function returns, and the mutex goes to an unsignaled state to ensure that no other threads waiting on the same semaphore can continue. As subsequent threads attempt to wait on the mutex object, they will be blocked. When a thread is done using a mutex, it can call
ReleaseMutex, and the next blocked thread is unblocked and granted ownership of the mutex. The program that illustrates the use of the matrix has four threads that do nothing more than count. Each thread's count is displayed in a different textbox.
The source code that each one of the four threads executes is given below. I've inserted a call to
Sleep into the code to cause it to run longer so that you can more easily observe the user interface as the threads execute.
int index = Interlocked.Increment(ref lastIndex);
using (NativeSync.Mutex m = new NativeSync.Mutex(MutexName,false))
for (int i = 0; (i < 50) && (_continueRunning); ++i)
When the code is run, only one of the counters executes at a time. Once it completes its work, the next counter will begin since the mutex will only allow one thread into the counting loop at a time.
Semaphores are similar to mutexes. It also limits the number of threads that can access a resource. Unlike the mutex, you can use semaphores to allow more than one thread to access a resource. A semaphore has a count attribute. The count can be 0 or greater, up to a maximum amount that is decided when the semaphore is created. When the count is greater than zero, the semaphore is in a signaled state. When a thread waits on a semaphore, if the semaphore is in a signaled state (which would mean the count is greater than zero), then the count is decremented. When the thread is done using the resource, it should call
ReleaseSemaphore to increment the count.
To demonstrate the use of a semaphore, I've taken the same program that waits on a mutex and modified it to wait on a semaphore instead. The semaphore used in this code example allows up to two threads to access it. So, when this program is run, you will see two counters working at a time.
The Windows Mobile Operating System offers a lot more synchronization functionality than described here. I only wanted to concentrate on events and their derivatives in this paper. The synchronization functions also support interprocess communication, monitoring a process for termination, and many other items of functionality. (See the MSDN documentation.)