Windows 上的事件和 Posix 上的互斥/条件变量用于实现可等待事件,如果没有线程被阻塞怎么办?

问题描述 投票:0回答:2

对于 Windows 上的事件,如果没有线程在等待,则事件对象的状态保持有信号状态。如果 pthread_cond_signal 会发生什么,如果没有线程被阻塞会发生什么?

events pthreads posix win32-process
2个回答
2
投票

对于

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 (...)
 


0
投票
有些人声称使用 IPC(进程间通信)信号量来“模拟”MS Windows 的行为(Windows 事件与 POSIX 条件变量相比)。

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 事件行为,即一个线程(生产者)必须向等待此事件的另一个线程(消费者)发出某些信号。

© www.soinside.com 2019 - 2024. All rights reserved.