Linux上的pthread条件变量,奇怪的行为

时间:2010-03-18 17:09:49

标签: linux api synchronization pthreads

我正在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(),每个等待进程都应该唤醒,而不仅仅是一个(但是,并不总是相同)。

4 个答案:

答案 0 :(得分:4)

你的condvar和mutex都有set the PTHREAD_PROCESS_SHARED attribute吗?

对于Linux ,请参阅以下man页:

方法,类型,常量等通常在/usr/include/pthread.h/usr/include/nptl/pthread.h中定义。

答案 1 :(得分:3)

在您的流程实际调用pthread_cond_wait()之前,您是否测试了某些条件?我问,因为这是一个非常常见的错误:您的流程必须致电wait(),除非您确定某个流程会调用signal()(或broadcast()

汇总此代码(来自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 <= y)条件为真,就从其他进程发出信号,它将无法工作,因为信号只唤醒已经在等待的进程。如果在其他进程调用signal()之前调用wait(),则信号将丢失,等待进程将永远等待。

编辑:关于while循环。 当您从另一个进程发信号通知一个进程时,它被设置在“就绪列表”上但不一定被安排,并且您的条件(x <= y)可能会再次改变,因为没有人持有该锁。这就是为什么每次你要等待时都要检查自己的状况。它应始终为wakeup -> check if the condition is still true -> do work

希望很清楚。

答案 2 :(得分:1)

文档说它应该有用......你确定它与其他线程看到的条件值相同吗?

这是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 */

答案 3 :(得分:0)

最后一张海报所说的是正确的。整个cond变量情况正常工作的关键是cond-var在等待之前没有发出信号。它严格地是当其他人(单人或多人)等待时使用的信号。当没有人在等待时,它实际上是一个NOP。哪,顺便说一下,我不相信它应该如何工作,但它是如何运作的。

拉​​里