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 的奇怪行为

Linux系统编程-(pthread)线程通信(条件变量)

pthread_cond_destroy() 挂起的奇怪行为

linux pthread和java thread的是/非守护线程的行为

Linux 条件变量函数signal和wait补充