c - 理解 pthread_cond_wait() 和 pthread_cond_signal()

标签 c multithreading posix mutex wait

我以这段代码为例,其中创建了两个线程,然后看起来像使用 pthread_cond_wait() 来挂起该线程,直到它准备好通过使用 pthread_cond_signal() 再次工作。我的问题是如果多个线程同时等待怎么办?执行 pthread_cond_signal() 如何选择正确的线程来唤醒?有没有办法选择唤醒特定的线程?假设我有一个生产者线程,它将客户订单放入单独的队列中,其中每个队列由一个线程管理。如果两个消费者线程因队列中没有任何内容而被 wait() 挂起,但生产者线程仅将订单插入其中一个消费者队列中,我们到底如何区分呢?如果这是不可能的,那么我可以使用什么其他方法来完成我想要的事情?

这里是一个示例代码,因为 stackoverflow 喜欢代码...不太相关: 示例

#define _MULTI_THREADED
#include <pthread.h>
#include <stdio.h>
#include "check.h"

/* For safe condition variable usage, must use a boolean predicate and  */
/* a mutex with the condition.                                          */
int                 workToDo = 0;
pthread_cond_t      cond  = PTHREAD_COND_INITIALIZER;
pthread_mutex_t     mutex = PTHREAD_MUTEX_INITIALIZER;

#define NTHREADS      2

void *threadfunc(void *parm)
{
  int           rc;

  while (1) {
    /* Usually worker threads will loop on these operations */
    rc = pthread_mutex_lock(&mutex);
    checkResults("pthread_mutex_lock()\n", rc);

    while (!workToDo) {
      printf("Thread blocked\n");
      rc = pthread_cond_wait(&cond, &mutex);
      checkResults("pthread_cond_wait()\n", rc);
    }
    printf("Thread awake, finish work!\n");

    /* Under protection of the lock, complete or remove the work     */
    /* from whatever worker queue we have. Here it is simply a flag  */
    workToDo = 0;

    rc = pthread_mutex_unlock(&mutex);
    checkResults("pthread_mutex_lock()\n", rc);
  }
  return NULL;
}

int main(int argc, char **argv)
{
  int                   rc=0;
  int                   i;
  pthread_t             threadid[NTHREADS];

  printf("Enter Testcase - %s\n", argv[0]);

  printf("Create %d threads\n", NTHREADS);
  for(i=0; i<NTHREADS; ++i) {
    rc = pthread_create(&threadid[i], NULL, threadfunc, NULL);
    checkResults("pthread_create()\n", rc);
  }

  sleep(5);  /* Sleep is not a very robust way to serialize threads   */

  for(i=0; i<5; ++i) {
    printf("Wake up a worker, work to do...\n");

    rc = pthread_mutex_lock(&mutex);
    checkResults("pthread_mutex_lock()\n", rc);

    /* In the real world, all the threads might be busy, and        */
    /* we would add work to a queue instead of simply using a flag  */
    /* In that case the boolean predicate might be some boolean     */
    /* statement like: if (the-queue-contains-work)                 */
    if (workToDo) {
       printf("Work already present, likely threads are busy\n");
    }
    workToDo = 1;
    rc = pthread_cond_signal(&cond);
    checkResults("pthread_cond_broadcast()\n", rc);

    rc = pthread_mutex_unlock(&mutex);
    checkResults("pthread_mutex_unlock()\n", rc);
    sleep(5);  /* Sleep is not a very robust way to serialize threads */
  }

  printf("Main completed\n");
  exit(0);
  return 0;
}
Output:

Enter Testcase - QP0WTEST/TPCOS0
Create 2 threads
Thread blocked
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Main completed 

最佳答案

实际上,只有一个线程被唤醒,你无法控制它是哪一个。

(pthread_cond_signal 唤醒至少一个等待给定条件变量的线程,并且选择的线程由调度策略确定。)

就您的情况而言,您需要重新考虑条件变量 (condvar) 表示的“条件”的含义。

如果 condvar 确实意味着“生产者已将一个项目添加到多个队列之一,每个队列都有一个专用的消费者”,那么您应该 pthread_cond_broadcast 来唤醒每个队列的消费者并让唤醒的线程弄清楚是否有工作要做。或者,您可以将条件重新转换为“生产者已将一项添加到此队列,该队列具有专用消费者”,并为每个队列使用一个 condvar。

关于c - 理解 pthread_cond_wait() 和 pthread_cond_signal(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20277033/

相关文章:

c - 返回定义(开关)

java - ExecutorService java 可能的线程泄漏

c - 避免警告 : expected ‘const struct aiocb * const*’ but argument is of type ‘struct aiocb **’

c - getnameinfo 的签名在 glibc 版本之间发生变化,我该如何匹配它?

c - Linux 上的最大主机名长度

python - 从 python 调用 c 程序时将数组传递给子进程模块的问题

c++ - 寄存器分配算法

java - java中多线程的意外答案

c - 尽管代码编译正确,但 Vim 显示警告

c++ - 如何让线程等待而不轮询?