pthread_cond_wait()的使用方法


/************pthread_cond_wait()的使用方法**********/
pthread_mutex_lock(&qlock);
pthread_cond_wait(&qready, &qlock);
pthread_mutex_unlock(&qlock);
/*****************************************************/
The mutex passed to pthread_cond_wait protects the condition.The caller passes it locked to the function, which then atomically places the calling thread on the list of threads waiting for the condition and unlocks the mutex. This closes the window between the time that the condition is checked and the time that the thread goes to sleep waiting for the condition to change, so that the thread doesn't miss a change in the condition. When pthread_cond_wait returns, the mutex is again locked.
上面是APUE的原话,就是说pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t*mutex)函数传入的参数mutex用于保护条件,因为我们在调用pthread_cond_wait时,如果条件不成立我们就进入阻塞,但是进入阻塞这个期间,如果条件变量改变了的话,那我们就漏掉了这个条件。因为这个线程还没有放到等待队列上,所以调用pthread_cond_wait前要先锁互斥量,即调用pthread_mutex_lock()pthread_cond_wait在把线程放进阻塞队列后,自动对mutex进行解锁,使得其它线程可以获得加锁的权利。这样其它线程才能对临界资源进行访问并在适当的时候唤醒这个阻塞的进程。当pthread_cond_wait返回的时候又自动给mutex加锁。
实际上边代码的加解锁过程如下:
/************pthread_cond_wait()的使用方法**********/
pthread_mutex_lock(&qlock); /*lock*/
pthread_cond_wait(&qready, &qlock); /*block-->unlock-->wait() return-->lock*/
pthread_mutex_unlock(&qlock); /*unlock*/
/*****************************************************/

http://blog.chinaunix.net/space.php?uid=20807123&do=blog&id=1833990


了解 pthread_cond_wait() 的作用非常重要 -- 它是 POSIX 线程信号发送系统的核心,也是最难以理解的部分。
首先,让我们考虑以下情况:线程为查看已链接列表而锁定了互斥对象,然而该列表恰巧是空的。这一特定线程什么也干不了 -- 其设计意图是从列表中除去节点,但是现在却没有节点。因此,它只能:

锁定互斥对象时,线程将调用 pthread_cond_wait(&mycond,&mymutex)pthread_cond_wait() 调用相当复杂,因此我们每次只执行它的一个操作。

pthread_cond_wait() 所做的第一件事就是同时对互斥对象解锁(于是其它线程可以修改已链接列表),并等待条件 mycond 发生(这样当 pthread_cond_wait() 接收到另一个线程的信号时,它将苏醒)。现在互斥对象已被解锁,其它线程可以访问和修改已链接列表,可能还会添加项。 【要求解锁并阻塞是一个原子操作

此时,pthread_cond_wait() 调用还未返回。对互斥对象解锁会立即发生,但等待条件 mycond 通常是一个阻塞操作,这意味着线程将睡眠,在它苏醒之前不会消耗 CPU 周期。这正是我们期待发生的情况。线程将一直睡眠,直到特定条件发生,在这期间不会发生任何浪费 CPU 时间的繁忙查询。从线程的角度来看,它只是在等待 pthread_cond_wait() 调用返回。

现在继续说明,假设另一个线程(称作“2 号线程)锁定了 mymutex 并对已链接列表添加了一项。在对互斥对象解锁之后,号线程会立即调用函数 pthread_cond_broadcast(&mycond)。此操作之后,号线程将使所有等待 mycond 条件变量的线程立即苏醒。这意味着第一个线程(仍处于 pthread_cond_wait() 调用中)现在将苏醒。
  现在,看一下第一个线程发生了什么。您可能会认为在 号线程调用 pthread_cond_broadcast(&mymutex) 之后,号线程的 pthread_cond_wait() 会立即返回。不是那样!实际上,pthread_cond_wait() 将执行最后一个操作:重新锁定 mymutex。一旦 pthread_cond_wait() 锁定了互斥对象,那么它将返回并允许 号线程继续执行。那时,它可以马上检查列表,查看它所感兴趣的更改。

个过程非常复杂,因此让我们先来回顾一下。第一个线程首先调用:
  pthread_mutex_lock(&mymutex);
  然后,它检查了列表。没有找到感兴趣的东西,于是它调用:
  pthread_cond_wait(&mycond, &mymutex);
  然后pthread_cond_wait() 调用在返回前执行许多操作:
  pthread_mutex_unlock(&mymutex);
  它对 mymutex 解锁,然后进入睡眠状态,等待 mycond 以接收 POSIX 线程信号。一旦接收到信号(加引号是因为我们并不是在讨论传统的 UNIX 信号,而是来自 pthread_cond_signal() 或 pthread_cond_broadcast() 调用的信号),它就会苏醒。但 pthread_cond_wait() 没有立即返回 ---- 它还要做一件事:重新锁定 mutex
pthread_mutex_lock(&mymutex);
pthread_cond_wait() 知道我们在查找 mymutex “背后的变化,因此它继续操作,为我们锁定互斥对象,然后才返回。

http://hi.baidu.com/nkhzj/blog/item/f5480d4f740f7f35aec3ab4b.html


#include <pthread.h>
#include <unistd.h>

static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

struct node 

{
int n_number;
struct node *n_next;
} *head = NULL;

/*[thread_func]*/
static void cleanup_handler(void *arg)
{
  printf("Cleanup handler of second thread./n");
  free(arg);
  (void)pthread_mutex_unlock(&mtx);
}
static void *thread_func(void *arg)
{
  struct node *p = NULL;

pthread_cleanup_push(cleanup_handler, p);
  while (1) 

{
       pthread_mutex_lock(&mtx); //这个mutex主要用来保证pthread_cond_wait的并发性

/*下面这个while要特别说明一下,单个pthread_cond_wait功能很完善,为何这里 要有一个while (head == NULL)呢?因为pthread_cond_wait里的线程可能会被意外 唤醒,如果这个时候head != NULL,则不是我们想要的情况。这个时候,应该让 线程继续进入pthread_cond_wait*/
while (head == NULL) 

{  

/* pthread_cond_wait会先解除之前的 pthread_mutex_lock锁定的mtx,然后阻 塞在等待列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立 而被唤醒,唤醒后,该进程会先锁定pthread_mutex_lock(&mtx);,再读取资源 用这个流程是比较清楚的/*block-->unlock-->wait() return-->lock*/

pthread_cond_wait(&cond, &mtx);  

}
  p = head;
  head = head->n_next;
  printf("Got %d from front of queue/n", p->n_number);
  free(p);
  pthread_mutex_unlock(&mtx); //临界区数据操作完毕,释放互斥锁
 }
 pthread_cleanup_pop(0);
 return 0;

}

int main(void)
{
  pthread_t tid;
  int i;
  struct node *p;

/*子线程会一直等待资源,类似生产者和消费者,但是这里的消费者可以是多个消费者, 而不仅仅支持普通的单个消费者,这个模型虽然简单,但是很强大*/
  pthread_create(&tid, NULL, thread_func, NULL);  /*[tx6-main]*/
  for (i = 0; i < 10; i++) 

{
  p = malloc(sizeof(struct node));
  p->n_number = i;
  pthread_mutex_lock(&mtx); //需要操作head这个临界资源,先加锁,
  p->n_next = head;
  head = p;
  pthread_cond_signal(&cond);
  pthread_mutex_unlock(&mtx); //解锁
  sleep(1);
  }
  printf("thread 1 wanna end the line.So cancel thread 2./n"); 

/*关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,子线程会在最近 的取消点退出线程,而在我们的代码里,最近的取消点肯定就是 pthread_cond_wait()了。*/
  pthread_cancel(tid); 

pthread_join(tid, NULL);
  printf("All done -- exiting/n");
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值