Post by David SchwartzPost by Joe SeighPulseEvent is broken so just don't use it. You don't need it anyway.
It's not just PulseEvent that's broken. The same thing would happen if
you unblocked the event and then blocked it again yourself. The
brokenness in PulseEvent means that the thread that picks up the event
must re-block it if you don't want too many threads to wake. This
significantly complicates using events.
Post by Joe SeighEvents are perfectly usable. I've used them for things like a priority
queue, etc... I don't think there's anything you can't do with an Event
that you can do with a condition variable, just not the same way.
They're different, not the same as, condition variables to answer
the OP's question.
It's very, very hard to ensure that you don't miss wakeups. Most of the
patterns I've seen using events live with the risk that a wakeup will
be missed and always set a fairly short timeout in the event wait to
ensure that a lost wakeup doesn't stall indefinitely.
So you're familiar with Event anti-patterns. Good for you.
Post by David SchwartzPost by Joe SeighAnd it's not that hard to get Event based code right once you use
the right synchronization patterns. And easy to get wrong if you
use the wrong synchronization pattern. So just don't use condvar
based patterns with Events. But please feel free to ignore this
and use the difficulty of implementing a condvar design pattern with
an Event as an example of why Events are problematic.
You can't have it both ways. You can't say that it's not hard to get
event based code right and at the same time say it's difficult to
implement a condvar design pattern. Condvar design patterns mirror a
huge number of real-world synchronization needs.
You're just saying that. Condvar design patterns are more natural
for you because that's the only thing you know.
Post by David SchwartzLet's take something ridiculously simple -- a queue. You add objects,
you pop objects, you block on the queue. Using events, how hard is it
to make sure that a thread that blocks on the queue never misses a
wakeup without a thundering herd if many threads are waiting?
Not very hard. The way to use Events is to associate it with
a a specific condition. In this case, the queue being empty.
Any code that toggles that condition, sets or resets the Event
appropiately while holding a lock.
To dequeue
EnterCriticalSection(&cs);
while (queue.isEmpty()) {
LeaveCriticalSection(&cs);
WaitForSingleObject(hEvent, INFINITE);
EnterCriticalSection(&cs);
}
item = queue.pop();
if (queue.isEmpty())
ResetEvent(hEvent);
LeaveCriticalSection(&cs);
return item;
To enqueue
EnterCriticalSection(&cs);
bool wasEmpty = queue.isEmpty();
queue.push(item);
if (wasEmpty)
SetEvent(hEvent);
LeaveCriticalSection(&cs);
or something like that.
Though in the case of a queue a semphore might be more appropiate than
an event object especially if you though thundering herd was a problem.
Using pthread_cond_signal with a condvar to avoid thundering herd is
probably a little bit dangerous since the dequeueing threads have to
remember to wake up another waiting thread. And it easy to have the
signal go to a wrong thread. This problem has been discussed before
on c.p.t. A semaphore would also probably be better than a condvar
in this case.
You might argue using events forces cleaner designs since you have to
associate events with specific conditions. Condvars allow you to be
non specific and not make it clear what condition or conditions you
intend to signal.
--
Joe Seigh
When you get lemons, you make lemonade.
When you get hardware, you make software.