Question: What is the life of an event? Is there a life timeout for a
signaled event? Is there a Queue for signaled events and if so how deep is
it?
Is there something I missed ( of course there is, but be gentle!)
Ron H.
I've built a few similar designs and have not seen such a problem. I
suspect you have a race or overlap condition. I.e., if you set an event that
is already set then only one event will be detected, not two. To avoid this
situation I generally prefer to make the threads message driven, since that
gives you a queue of signals to the thread.
--
Scott McPhillips [VC++ MVP]
"Ron H" <rnh...@nospam.net> wrote in message
news:CLVIm.2988$ky1....@newsfe14.iad...
There is no timeout on a signaled event; there is only timeout on a WFSO/WFMO. Now one of
the potential problems of WFMO is "starvation", that is, if a lower-numbered handle is
often signaled, the higher-numbered handles will never be processed. Suppose you had a
handle H[2] which was signaled once every 100ms, and a handle H[3] which was signaled at
some other rate (more often or less often doesn't matter). Now suppose that to process
H[2] takes, on the average, 150ms. Then every time you return to the WFMO, H[2] is
signaled, and H[3], although it has been signaled since last Tuesday, will never be seen.
Note that there is no queue; there is no concept of queuing logic at all. Events are
handled in a strictly priority order, with the lowest-numbered event taking priority.
On solution we once applied to this problem was "round robin" scheduling of the WFMO. So
H[0] (the shutdown event) remained at location 0. But after each non-H[0] completion of
WFMO (or result > 1 and result < array element count), we did a "rotation" of the
elements; that is, element 1 was stored in a temp. The code was
HANDLE t = H[1];
for(int i = 1; i < count -1; i++)
H[i] = H[i] + 1;
H[count - 1] = t;
This was of course a bit more complex because we had to rotate the accompanying array of
elements that said what to do, but you get the idea. This guaranteed that eventually
every event became the "most important" event.
The problem was caused by the fact that every once in a while, a database query initiated
by a thread took a very long time. Once that happened, the world started falling apart
because that event was always signaled.
This was frankly a hack because there were something like 250K lines of source and the
original programmer had "just growed" the logic, and there was neither time nor budget to
rewrite the code to do something better.
Another way to handle this is to not use an event array at all, but instead use a queue of
elements. You can do this with mutex/CRITICAL_SECTION + Semaphore (see my essay on
semaphores) or what I am more likely to do, use an I/O Completion Port as my queue. Then
the threads, instead of doing a SetEvent, will do a PostQueuedCompletionStatus into the
I/O Completion Port and the receiving thread will do a GetQueuedCompletionStatus from that
port. This guarantees that events are always handled in FIFO order, and there is no
starvation. You can read my essay on I/O Completion Ports. To do a shutdown, you
PostQueuedCompletionStatus of a value or set of values that are "out of band", that is,
can never be legal; this is the way to send a notice to terminate the thread. Or, if a
thread terminates, the last thing it does is send a value or set of values OOB to indicate
thread status, such as thread completion (I sometimes have different sets of values to
indicate successful completion and error completion). Also, check out my technique for
having an OnIdle handler that guarantees you won't "flood" the main GUI thread message
pump with messages and delay everything, and note also you need a timer to guarantee that
this special queue gets handled in a timely fashion.
joe
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Now I understand!!! Thanks Joe, I will go read your essay on I/O Completion
Ports...
Carry on!
Ron H.
I created a CRITICAL_SECTION FIFO, each set(int) stores the int in the next
available position in an array of ints and each Get() returns the oldest int
then shifts the array by 1. Then in the worker thread, the switch on
WaitForMultipleObjects() only gets either a 0 or 1 and on a 1 it gets the
next int in the FIFO and switches on that int to do the next operation.
Seems to work like a charm... Thanks!
Ron H.