Linux上的pthread条件变量,奇怪的行为
Posted
技术标签:
【中文标题】Linux上的pthread条件变量,奇怪的行为【英文标题】:pthread condition variables on Linux, odd behaviour 【发布时间】:2010-03-18 17:09:49 【问题描述】:我正在同步 Linux 上的读取器和写入器进程。
我有 0 个或多个进程(读取器)需要休眠,直到它们被唤醒、读取资源、重新休眠等等。请注意,我不知道任何时候有多少阅读器进程启动。 我有一个进程(写入器)在资源上写入,唤醒读取器并执行其业务,直到另一个资源准备好(详细地说,我开发了一个不饿死的读取器-写入器解决方案,但这并不重要)。
为了实现睡眠/唤醒机制,我使用 Posix 条件值 pthread_cond_t。客户端调用变量上的 pthread_cond_wait() 以休眠,而服务器执行 pthread_cond_broadcast() 将它们全部唤醒。正如手册中所说,我将这两个调用与相关 pthread 互斥锁的锁定/解锁包围在一起。
条件变量和互斥锁在服务器中初始化,并通过共享内存区域在进程之间共享(因为我不使用线程,而是使用单独的进程)我确定我的内核/系统调用支持它(因为我检查了 _POSIX_THREAD_PROCESS_SHARED)。
发生的情况是第一个客户端进程完美地休眠和唤醒。当我启动第二个进程时,它会阻塞它的 pthread_cond_wait() 并且 从不 唤醒,即使我确定(根据日志)调用了 pthread_cond_broadcast()。
如果我杀死第一个进程并启动另一个进程,它会完美运行。换句话说,条件变量 pthread_cond_broadcast() 似乎每次只唤醒一个进程。如果多个进程等待同一个共享条件变量,则只有第一个进程能够正确唤醒,而其他进程似乎忽略了广播。
为什么会有这种行为?如果我发送一个 pthread_cond_broadcast(),每个等待的进程都应该被唤醒,而不仅仅是一个(但是,并不总是同一个)。
【问题讨论】:
【参考方案1】:您在 condvar 和 mutex 上都有 set the PTHREAD_PROCESS_SHARED
attribute 吗?
对于 Linux 请参阅以下man
页面:
pthread_mutexattr_init
(附样品)
pthread_mutexattr_setpshared
pthread_condattr_init
pthread_condattr_setpshared
方法、类型、常量等通常在/usr/include/pthread.h
、/usr/include/nptl/pthread.h
中定义。
【讨论】:
弗拉德,我在 Linux 上,没有这样的属性(根据手册页)。 @james,检查你的头文件 (find /usr/include/ -type f | xargs egrep '(PTHREAD_PROCESS_SHARED|pthread_condattr_setpshared|pthread_mutexattr_setpshared)'
),它应该都在 /usr/include/pthread.h
中,即使在 Linux 上也是如此(毕竟它是 POSIX,而且我在我的 CentOS 4.x 上有它框。)
...这也带来了一个问题,当我们讨论这个问题时,您使用的是什么 Linux? :) (uname -a; cat /etc/issue
)【参考方案2】:
在您的流程实际调用 pthread_cond_wait()
之前,您是否测试了某些条件?我问是因为,这是一个非常常见的错误:您的进程必须不调用wait()
,除非您确定某些进程会调用signal()
(或broadcast()
)稍后 em>。
考虑此代码(来自 pthread_cond_wait
手册页):
pthread_mutex_lock(&mut);
while (x <= y)
pthread_cond_wait(&cond, &mut);
/* operate on x and y */
pthread_mutex_unlock(&mut);
如果您省略了while
测试,并且只要您的 (x wait() 之前调用了signal()
,则信号将丢失,等待进程将永远等待。
编辑:关于 while 循环。 当您从另一个进程向一个进程发出信号时,它被设置在“就绪列表”中,但不一定是预定的,并且您的条件(x wakeup -> check if the condition is still true -> do work。
希望很清楚。
【讨论】:
我不完全理解你的答案..添加一个while循环如何防止等待阻塞?【参考方案3】:文档说它应该可以工作...您确定它与其他线程正在查看的条件值相同吗?
这是来自opengroup.org的示例代码:
pthread_cond_wait(mutex, cond):
value = cond->value; /* 1 */
pthread_mutex_unlock(mutex); /* 2 */
pthread_mutex_lock(cond->mutex); /* 10 */
if (value == cond->value) /* 11 */
me->next_cond = cond->waiter;
cond->waiter = me;
pthread_mutex_unlock(cond->mutex);
unable_to_run(me);
else
pthread_mutex_unlock(cond->mutex); /* 12 */
pthread_mutex_lock(mutex); /* 13 */
pthread_cond_signal(cond):
pthread_mutex_lock(cond->mutex); /* 3 */
cond->value++; /* 4 */
if (cond->waiter) /* 5 */
sleeper = cond->waiter; /* 6 */
cond->waiter = sleeper->next_cond; /* 7 */
able_to_run(sleeper); /* 8 */
pthread_mutex_unlock(cond->mutex); /* 9 */
【讨论】:
【参考方案4】:最后一张海报说的是正确的。整个 cond-variable 情况正常工作的关键是 cond-var 在等待之前没有发出信号。它严格来说是其他人(单个或多个)等待时使用的信号。当没有人在等待时,它实际上是一个 NOP。顺便说一句,这不是我认为它应该如何工作,而是它如何工作。
拉里
【讨论】:
您应该将此作为评论发布,而不是作为新答案。以上是关于Linux上的pthread条件变量,奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章
pthread_cond_destroy() 挂起的奇怪行为