I have a Thread object that I made compatible with pevents WFMO. In Win32, a thread HANDLE is "signaled" when the thread exits. Internal to the Thread object is a m_evThreadExited pevent (manual reset = true) that is signaled when the Thread function exits (via an internal thread function wrapper that signals the event when the user's thread function returns).
Assuming you have a similar wrapper for sem_t, it could also have an internal m_evSemAcquired (manual reset = false) that is used in WFMO calls. The problem becomes who is going to signal this event? The first thing that comes to mind is a dedicated thread that calls sem_trywait() and signals m_evSemAcquired once it succeeds. Something like this (off the top of my head):
Code:
Semaphore sem;
...
Thread A
sem.StartAsyncWait();
int status = WFMO(...);
sem.StopAsyncWait();
...
Thread B
sem.StartAsyncWait();
int status = WFMO(...);
sem.StopAsyncWait();
Across thread A and B, there would only be one async-wait-thread that services the sem instance. The Start/Stop calls would need to be reference counted so that only the last Stop really stops the async-wait-thread - and only the first Start actually starts the thread. Because m_evSemAcquired is an auto-reset event, only one of the WFMO() calls will be the winner once the sem is acquired.
So this won't really work as-is. Both WFMO calls could return some other index even though sem was acquired by the thread. This could be fixed by letting Stop know if the sem was the winner:
Code:
sem.StartAsyncWait();
int status = WFMO(...);
sem.StopAsyncWait(status == semIndex);
...
void Semaphore::StopAsyncWait(bool bWinner)
{
[mutex this method with Start method]
if (bWinner)
m_bHaveWinner = true;
--m_refCount;
if (m_refCount == 0)
{
this->DoStopAsncWait();
int sem_val;
sem_getvalue(&m_s, &sem_val);
const bool bSemAcquired = (sem_val <= 0);
bool bDoPost = !m_bHaveWinner && bSemAcquired;
if (m_evSemAcquired.IsSignaled())
{
// async-wait-thread acquired us outside of last WFMO call
m_evSemAcquired.Reset();
bDoPost = true;
}
if (bDoPost)
sem_post(&m_s); // undo "accidental" acquire
m_bHaveWinner = false; // or reset on first Start call
}
}
This allows any acquisition of sem that didn't result in a WFMO() winner to be "undone". Note that "sem_val <= 0" assumes that Semaphore is really a mutex (sem value is 0 or 1). For a generic semaphore, you would need the track the sem value before and after the async-wait-thread runs. If the sem value decreased, then you know the thread acquired it.
I think this works
gg