理解pthread_cond_wait()和pthread_cond_signal()

时间:2013-11-29 01:24:05

标签: 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 

1 个答案:

答案 0 :(得分:2)

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

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

在您的情况下,您需要重新考虑条件变量(condvar)所代表的“条件”的含义。

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