How to detect slipped event error?

Common error in auto reset event

In Win32 API, you can use an "event object" to synchronize multiple threads. An event has one of two state: signaled or not-signaled. When it’s not-signaled, the waiting thread is blocked on WaitForSingleObject call, and it’s unblocked when the event is signaled.

You can signal a event by SetEvent() API function.

However, thread synchronization with event objects is known to be error prone. One typical error is "slipped event" where SetEvent() is called on already signaled event and does not have any effect. Let’ say, you write a one-length FIFO, where one thread push a value and the other thread pulls it.

// variable to pass value from push thread
// to pull thread.
int plate;

// event is created with auto-reset, initial
// value is not signaled.
HANDLE hasItem = CreateEvent(NULL, FALSE, FALSE, NULL);

void push(int item){
plate = item;
SetEvent(hasItem);
}

int pull(){
WaitForSingleObject(hasItem, INFINITE);
return plate;
}

If push() is called twice before pull(), value in plate is overwritten and lost. Slipped event error is very common and hard to avoid. It’s also difficult to debug because the effect may be visible long time later.

Slipped event debugging technique

There is a way to make your life easier: Use semaphore instead of auto-reset event.

If you read the MSDN carefully, you may find that auto-reset event is actually same as semaphore with maximum count = 1. However, there is a big advantage of semaphore over event. When you call ReleaseSemaphore (SetEvent of semaphore) on a signaled semaphore (count = 1), it returns FALSE. You can detect slipped event by checking the return value of ReleaseSemaphore.

// variable to pass value from push thread
// to pull thread.
int plate;

// semaphoe with initial value is 0, maximum
// value is 1. It's equivalent to auto-reset
// event.
HANDLE hasItem = CreateSemaphoe(NULL, 0, 1, NULL);

void push(int item){
plate = item;
BOOL bResult = ReleaseSemaphoe(hasItem, 1, NULL);
assert(bResult);
}

int pull(){
WaitForSingleObject(hasItem, INFINITE);
return plate;
}

Advertisements

About Moto

Engineer who likes coding
This entry was posted in Tips. Bookmark the permalink.

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