pthread条件变量

pthread条件变量等待条件有两种方式:无条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。  
   
 无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait())的竞争条件。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。

 1 #include <pthread.h>
 2 #include <unistd.h>
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 
 6 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
 7 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 8  
 9 struct node {
10     int n_number;
11     struct node *n_next;
12 } *head = NULL;
13  
14  // 线程清理函数
15 static void cleanup_handler(void *arg)
16 {
17     printf("Cleanup handler of second thread.\n");
18     free(arg);
19     (void)pthread_mutex_unlock(&mtx);
20 }
21 
22 static void *thread_func(void *arg)
23 {
24     struct node *p = NULL;
25  
26     pthread_cleanup_push(cleanup_handler, p);
27     while (true) {
28         //这个mutex主要是用来保证pthread_cond_wait的并发性
29         pthread_mutex_lock(&mtx);
30 
31         /*
32         因为pthread_cond_wait里的线程可能会被意外唤醒,
33         如果这个时候head != NULL,则不是我们想要的情况。
34         这个时候,应该让线程继续进入pthread_cond_wait
35         */
36         while (head == NULL) {                     
37             /*
38             pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,
39             然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,
40             唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);再读取资源                 
41             用这个流程是比较清楚的block-->unlock-->wait() return-->lock
42             */
43             pthread_cond_wait(&cond, &mtx);  
44         }
45         p = head;
46         head = head->n_next;
47         printf("Got %d from front of queue\n", p->n_number);
48         free(p);
49         //临界区数据操作完毕,释放互斥锁
50         pthread_mutex_unlock(&mtx);
51     }
52     pthread_cleanup_pop(0);
53     return 0;
54 }
55  
56 int main(void)
57 {
58     pthread_t tid;
59     int i;
60     struct node *p;
61     pthread_create(&tid, NULL, thread_func, NULL); 
62 
63     for (i = 0; i < 3; i++) {
64         p = (struct node*)malloc(sizeof(struct node));
65         p->n_number = i;
66 
67         // 加锁->signal->解锁
68         pthread_mutex_lock(&mtx);
69         p->n_next = head;
70         head = p;
71         pthread_cond_signal(&cond);
72         pthread_mutex_unlock(&mtx);
73         sleep(1);
74     }
75     printf("cancel thread\n");
76     /*
77     从外部终止子线程,子线程会在最近的取消点,退出线程
78     最近的取消点肯定就是pthread_cond_wait()了。
79     */
80     pthread_cancel(tid);
81     // 等待cancel完成,不然可能不会执行到cleanup。
82     pthread_join(tid, NULL);
83     printf("All done -- exiting\n");
84     return 0;
85 }

pthread_cleanup_push来注册清理函数rtn,这个函数有一个参数arg。在以下三种情形之一发生时,注册的清理函数被执行:
    1)调用pthread_exit。
    2)作为对取消线程请求(pthread_cancel)的响应。
    3)以非0参数调用pthread_cleanup_pop。
注意:
    1)如果线程只是由于简单的返回而终止的,则清除函数不会被调用。
    2)如果pthread_cleanup_pop被传递0参数,则清除函数不会被调用,但是会清除处于栈顶的清理函数。

posted @ 2018-09-26 20:46  linyx  阅读(1504)  评论(0编辑  收藏  举报