Aha! I see the problem. Indeed if statepart == -1, then a waiter can
constantly spin in wait() - consume a semaphore count, see no
generation change, release a semaphore count, and so on.
It seems that this variant of eventcount is not "all that good" in
several aspects:
http://groups.google.com/group/comp.programming.threads/browse_frm/thread/9461b41709e4063a
For your particular problem you may try the following algorithm:
class eventcount
{
public:
eventcount(HANDLE g_sema, unsigned volatile* waiter_count)
{
waiter_count_ = waiter_count;
sema_ = g_sema;
}
void prepare_wait()
{
_InterlockedIncrement(waiter_count_);
}
void retire_wait()
{
_InterlockedDecrement(waiter_count_);
}
void wait()
{
WaitForSingleObject(sema_, INFINITE);
}
void signal()
{
_mm_mfence();
signal_relaxed();
}
void signal_relaxed()
{
long wc = *waiter_count_;
for (;;)
{
if (wc <= 0)
return;
unsigned wc0 = _InterlockedCompareExchange(waiter_count_, wc - 1,
wc);
if (wc0 == wc)
{
ReleaseSemaphore(sema_, 1, 0);
return;
}
wc = wc0;
}
}
private:
long volatile* waiter_count_;
HANDLE sema_;
};
I've simplified it by completely removing "wait generations". Since in
your problem all waiters are identical (it's OK to wakeup any waiter),
it should not be a problem.
CAUTION: the algorithm is untested and typed in notepad.
--
Dmitry Vyukov