对于 Windows 上的事件,如果没有线程在等待,则事件对象的状态保持有信号状态。如果 pthread_cond_signal 会发生什么,如果没有线程被阻塞会发生什么?
对于
pthread_cond_signal()
...如果在那个时刻没有线程等待,什么也没有发生,什么也没有发生——特别是,信号被完全忘记了,就好像它从未发生过 .
恕我直言,POSIX“条件变量”的命名很糟糕,因为名称表明“条件变量”有一个值,并且很自然地假设该值可能会收集待处理的信号。没有东西会离事实很远。 (为此你需要“信号量”。)与“条件”相关的“状态”才是重要的。需要等待“状态”具有特定值的线程将:
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) ;
更新“状态”以便其他线程现在可以继续的线程将:
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:标准明确允许
pthread_cond_signal()
启动一个、部分或所有等待者...因此等待者中的
while(...)
循环...以及“声明”信号的等待者需要更新状态,以便任何其他线程将在其中循环
while (...)
IPC 信号量的问题在于它们在 UNIX 机器中的“全局管理”,即使用被 SIGKILL 信号杀死的信号量的进程将保留已分配的信号量,直到下一次重新启动(或直到有人主动删除它们) - 您甚至可能信号量用完了,这真的很糟糕。
POSIX 线程、互斥体和条件变量用于进程内通信(而非进程间通信)。我的解决方案除了使用一对(MUTEX,CONDVAR)之外还使用原子计数器来修复“忘记”信号的问题(如果当前没有人在等待)(这里没有错误处理):
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);
原子变量的第一次检查是一种“快速路径”,无需首先锁定互斥体(仍然在 CPU、CPU 内核等之间同步)。这是一个非常简单的例子,可以通过添加pthread_cond_timedwait来修改。此外,如果您想完全重置事件,请将所有出现的“__sync_fetch_and_sub(&signalled, 1)”替换为“__sync_fetch_and_and(&signalled, 0)”。
这只是实现了“生产者-消费者模式”的 Windows 事件行为,即一个线程(生产者)必须向等待此事件的另一个线程(消费者)发出某些信号。