Re: Waitable Timer - Proper Use



THIS POST IS A REPOST. MY APOLOGIES.

I have a common problem where there is a thread that sits in a loop
inserting objects into a priority queue that are to be processed at
specific future instants. Inside the loop, it waits on two things:

1. There is an object in the queue whose instant for processing has
arrived.
2. There is a new object to be placed in the queue.

Though I have not checked thoroughly, I suspect there will be a race
condition when I try to use waitable timers to solve this problem. The
race condition will result from #1: I will not be able to determine
which object's priority instant caused WaitForMultipleObjects to break.

Suppose I am waiting on a non-repeating synchronization timer.

PATHOLOGY:

1. The waitable timer is active but not signaled. The instant that is
defined inside the waitable timer is that for the highest-priority
object currently in the priority queue.
2. A request to put a new object into the queue arrives.
3. The instant at which processing should occur for the new object is
calculated. This instant *precedes* in time the instant currently
defined for the waitable timer, and therefore, should be processed
before the currently defined instant of the waitable timer.
4. The new instant and new object are placed in the priority queue.
Note that the top of the priority queue is now the new instant and its
new object, but the old instant is still the one inside the waitable
timer.
5. The waitable timer becomes signaled by the old instant.
6. We try to redefine the waitable timer to take on the new instant,
but we cannot, because the timer is already signaled. There is no
indication from CancelWaitable timer that an attempt to cancel failed.
7. We reenter the wait loop, and break because timer is signaled.
8. We see that loop broke because timer is signaled, but we have no
idea which instant, the old or the new, caused it to trigger.

How to fix?

-Le Chaud Lapin-

#define _WIN32_WINNT 0x0400

#include <windows.h>

int main (int argc, char *argv[], char *envp[])
{
HANDLE hTimer = CreateWaitableTimer (NULL, FALSE, NULL);
LARGE_INTEGER li = {0};
li.QuadPart = -1 * 10 * 1000 * 1000; // 1 second, change to 5
if you
like
BOOL bResult = SetWaitableTimer(hTimer, &li, 0, NULL, NULL,
FALSE);
DWORD dwResult = WaitForSingleObject(hTimer, INFINITE);
bResult = CancelWaitableTimer (hTimer);
return 0;
}

.


Loading