Reputation: 10582
In case of Events on Windows, If no threads are waiting, the event object's state remains signaled. What happens in case of pthread_cond_signal, what happens in case if no threads are blocked?
Upvotes: 1
Views: 999
Reputation: 23
Some people state to use IPC (InterProcess Communication) semaphores to 'emulate' the behaviour of MS Windows (Windows events compared to POSIX condition variables).
The problem with IPC semaphores is their 'global management' in your UNIX box, i.e. a process using semaphores that get killed by a SIGKILL signal will leave allocated semaphores allocated until the next reboot (or until someone actively removes them) - you may even run out of sempaphores, which is really bad.
POSIX thread, mutexes, and condition variables are for INTRAprocess communication (not INTER). My solution uses an atomic counter in addition to the pair of (MUTEX,CONDVAR) to fix the problem of 'forgotten' signals if noone is currently waiting for it (no error handling here):
pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t event_condvar = PTHREAD_COND_INITIALIZER;
volatile long event_counter = 0L;
(...)
/* how to signal: */
pthread_mutex_lock(&event_mutex);
__sync_fetch_and_add(&event_counter,1);
pthread_cond_signal(&event_condvar);
pthread_mutex_unlock(&event_mutex);
(...)
/* how to wait: */
if (__sync_fetch_and_and(&signalled, -1) > 0) /* optional fast path, no mutex lock */
{
__sync_fetch_and_sub(&signalled, 1);
return;
}
pthread_mutex_lock(&event_mutex);
if (__sync_fetch_and_and(&signalled, -1) > 0) /* check again, there might be happened something in between */
{
__sync_fetch_and_sub(&signalled, 1);
pthread_mutex_unlock(&event_mutex);
return;
}
pthread_cond_wait(&event_condvar, &event_mutex); /* implicitly unlocks mutex while waiting */
__sync_fetch_and_sub(&signalled, 1);
pthread_mutex_unlock(&event_mutex);
The first checking of the atomic variable is kind of a 'fast path' without locking the mutex first (still synchronized across CPUs, CPU cores, etc.).
This is a very simple example, which could be modified by adding pthread_cond_timedwait. Furthermore, if you want to fully reset the event, substitute all occurrences of '__sync_fetch_and_sub(&signalled, 1)' by '__sync_fetch_and_and(&signalled, 0)'.
This just implements the Windows event behaviour for the 'producer-consumer pattern' i.e. one thread (producer) has to signal something to ONE other thread (consumer) waiting for this event.
Upvotes: 0
Reputation:
For pthread_cond_signal()
... if there are no threads waiting at that exact moment, nothing happens, nothing at all -- in particular, the signal is completely forgotten, it is as if it had never happened.
IMHO POSIX "condition variables" are badly named, because the name suggests that the "condition variable" has a value, and it is natural to suppose that the value might collect pending signals. Nothing could be further from the truth. (For that you need "semaphores".)
The "state" associated with the "condition" is what matters. A thread which needs to wait for the "state" to have a particular value will:
pthread_mutex_lock(foo_mutex) ;
while (...state not as required...)
pthread_cond_wait(foo_cond, foo_mutex) ;
...perhaps update the state...
pthread_mutex_unlock(foo_mutex) ;
A thread which updates the "state" such that some other thread may now continue, will:
pthread_mutex_lock(foo_mutex) ;
...update the state...
if (...there may be a waiter...)
pthread_cond_signal(foo_cond) ;
pthread_mutex_unlock(foo_mutex) ;
NB: the standard explicitly allows pthread_cond_signal()
to start one, some or all waiters... hence the while(...)
loop in the waiter... and the waiter that "claims" the signal needs to update the state so that any other threads will loop in that while (...)
Upvotes: 3