通常,和pthread _cond_wait 配对使用的有pthread_cond_signal , 同时还有用于pthread_cond_t初始化的pthread_cond_init,销毁的pthread_cond_destroy函数,还有用于加锁保护的pthread_mutex_lock和pthread_mutex_unlock,稍后会对为什么进行加锁做解释。
初始化条件变量int pthread_cond_init(pthread_cond_t *cv, pthread_cond_attr *cattr);
函数返回值:返回0表示成功,其他都表示失败。对于函数的参数:pthread_cond_attr 是用来设置pthread_cond_t的属性,当传入的值是NULL的时候表示使用默认的属性。这个函数返回时,创建的条件变量保存在cv所指向的内存中。可以用宏PTHREAD_COND_INITIALIZER来初始化条件变量。但是请记住不能用多个线程初始化同一个条件变量,当一个线程要使用条件变量的时候确保它是未被使用的。
条件变量的销毁:int pthread_cond_destroy(pthread_cond_t *cv); 返回0表示成功,返回其他值都表示失败。
条件变量的使用: int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)以及 int pthread_cond_signal(pthread_cond_t *cv);
使用pthread_cond_wait方式如下:
pthread _mutex_lock(&mutex)
while或if(线程执行的条件是否成立)
pthread_cond_wait(&cond, &mutex);
线程执行
pthread_mutex_unlock(&mutex);
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.
接下来讲解使用while和if判断线程执行条件是否成立的区别。一般来说,在多线程资源竞争的时候,在一个使用资源的线程里面(消费者)判断资源是否可用,不可用便调用pthread_cond_wait,在另一个线程里面(生产者)如果判断资源可用的话,则调用pthread_cond_signal发送一个资源可用信号。但是在wait成功之后,资源就一定可以被使用么,答案是否定的,如果同时有两个或者两个以上的线程正在等待此资源,wait返回后,资源可能已经被使用了,在这种情况下,应该使用:
while(resource == FALSE)
pthread_cond_wait(&cond, &mutex);
如果之后一个消费者,那么使用if就可以了。解释一下原因,分解pthread_cond_wait的动作为以下几步:
1,线程放在等待队列上,解锁
2,等待 pthread_cond_signal或者pthread_cond_broadcast信号之后去竞争锁
3,若竞争到互斥索则加锁。
上面讲到,有可能多个线程在等待这个资源可用的信号,信号发出后只有一个资源可用,但是有A,B两个线程都在等待,B比较速度快,获得互斥锁,然后加锁,消耗资源,然后解锁,之后A获得互斥锁,但他回去发现资源已经被使用了,它便有两个选择,一个是去访问不存在的资源,另一个就是继续等待,那么继续等待下去的条件就是使用while,要不然使用if的话pthread_cond_wait返回后,就会顺序执行下去。
下面来讲一下:pthread_cond_wait和pthread_cond_singal是怎样配对使用的:
等待线程:
pthread_cond_wait前要先加锁
pthread_cond_wait内部会解锁,然后等待条件变量被其它线程激活
pthread_cond_wait被激活后会再自动加锁
激活线程:
加锁(和等待线程用同一个锁)
pthread_cond_signal发送信号(阶跃信号前最好判断有无等待线程)
解锁
激活线程的上面三个操作在运行时间上都在等待线程的pthread_cond_wait函数内部。
1. #include<stdio.h>
2. #include<sys/types.h>
3. #include<stdlib.h>
4. #include<unistd.h>
5. #include<pthread.h>
6.
7. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
8. pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
9.
10. int count = 0;
11.
12. void *decrement(void *arg) {
13. "in derement.\n");
14. pthread_mutex_lock(&mutex);
15. if (count == 0)
16. pthread_cond_wait(&cond, &mutex);
17. count--;
18. "----decrement:%d.\n", count);
19. "out decrement.\n");
20. pthread_mutex_unlock(&mutex);
21. return NULL;
22. }
23.
24. void *increment(void *arg) {
25. "in increment.\n");
26. pthread_mutex_lock(&mutex);
27. count++;
28. "----increment:%d.\n", count);
29. if (count != 0)
30. pthread_cond_signal(&cond);
31. "out increment.\n");
32. pthread_mutex_unlock(&mutex);
33. return NULL;
34. }
35.
36. int main(int argc, char *argv[]) {
37. pthread_t tid_in, tid_de;
38. void*)decrement, NULL);
39. sleep(2);
40. void*)increment, NULL);
41. sleep(5);
42. pthread_join(tid_de, NULL);
43. pthread_join(tid_in, NULL);
44. pthread_mutex_destroy(&mutex);
45. pthread_cond_destroy(&cond);
46. return 0;
47. }
这个例子中, decrement函数中也可以使用while,读者可以换一下试试。
然后在给出一个生产者消费者的例子:
1. #include<stdio.h>
2. #include<stdlib.h>
3. #include<pthread.h>
4. #include<unistd.h>
5.
6. typedef struct node_s {
7. int data;
8. struct node_s *next;
9. }node_t;
10.
11. node_t *head = NULL;
12.
13. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
14. pthread_cond_t condition = PTHREAD_COND_INITIALIZER;
15.
16. void cleanup_handler(void *arg) {
17. "cleanup_handler is running.\n");
18. free(arg);
19. pthread_mutex_unlock(&mutex);
20. }
21.
22. void *thread_func(void *arg) {
23. node_t *p = NULL;
24. pthread_cleanup_push(cleanup_handler, p);
25. while (1) {
26. pthread_mutex_lock(&mutex);
27. while (NULL == head)
28. pthread_cond_wait(&condition, &mutex);
29. p = head;
30. head = head->next;
31. "process %d node.\n", p->data);
32. free(p);
33. pthread_mutex_unlock(&mutex);
34. }
35. pthread_cleanup_pop(0);
36. return NULL;
37. }
38.
39. int main(int argc, char *argv[]) {
40. pthread_t tid;
41. node_t *temp = NULL;
42. int i;
43. void*)thread_func, NULL);
44. for (i = 0; i < 10; i++) {
45. sizeof(node_t));
46. temp->data = i;
47. pthread_mutex_lock(&mutex);
48. temp->next = head;
49. head = temp;
50. pthread_cond_signal(&condition);
51. pthread_mutex_unlock(&mutex);
52. sleep(1);
53. }
54. pthread_cancel(tid);
55. pthread_join(tid, NULL);
56. return 0;
57. }