一.条件变量
线程间的同步还有一种情况:线程A需要等某个条件成立才能继续往下执行,当条件不成立时,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行。在pthread库中通过条件变量(Condition Variable)来阻塞等待一个条件,或者唤醒等待这个条件的线程,条件变量的初始化和销毁函数如下:
返回值:成功返回0,失败返回错误码。
和Mutex的初始化和销毁类似,如果Condition Variable是静态分配的,也可以用宏定义PTHREAD_COND_INITIALIAER初始化,相当于用pthread_cond_init初始化并且参数attr为NULL。 Condition Variable的操作可以用下列函数:
返回值:成功返回0,失败返回错误号
一个Condition Variable 总是和一个Mutex搭配使用的,一个线程可以调用pthread_cond_wait在一个Condition Variable 上阻塞等待,这个函数做已下三步:
(1)释放Mutex
(2)阻塞等待
(3)当被唤醒时,重新获得Mutex并返回
pthread_cond_timedwait函数还有一个额外的参数可以设定等待超时,如果到达了abstime所指定的时刻仍然没有别的线程来唤醒当前线程,就返回ETIMEDOUT。一个线程可以调用pthread_cond_signal唤醒在某个Condition Variable上等待的另一个线程,也可以调用pthread_cond_broadcast唤醒在这个Condition Variable上等待的所有线程。
二.演示生产者——消费者
生产者生产一个结构体串在链表的表头上,消费者从 表头取走结构体。
代码实现如下:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<pthread.h> 4 typedef int data_type; 5 typedef int* data_type_p; 6 typedef struct _node{ 7 struct _node* _next; 8 data_type _data; 9 }node_t,*node_p,**node_pp; 10 node_p head=NULL; 11 static pthread_mutex_t lock1=PTHREAD_MUTEX_INITIALIZER; 12 static pthread_mutex_t lock2=PTHREAD_MUTEX_INITIALIZER; 13 static pthread_mutex_t lock3=PTHREAD_MUTEX_INITIALIZER; 14 static pthread_cond_t need_product=PTHREAD_COND_INITIALIZER; 15 static node_p buy_node(data_type data) 16 { 17 node_p tmp=(node_t *)malloc(sizeof(node_t)); 18 if(tmp) 19 { 20 tmp->_data=data; 21 tmp->_next=NULL; 22 return tmp; 23 } 24 return NULL; 25 } 26 void init_list(node_pp head) 27 { 28 *head=buy_node(0); 29 } 30 void push_back(node_p head,data_type data) 31 { 32 node_p tmp=buy_node(data); 33 if(head->_next==NULL) 34 { 35 head->_next=tmp; 36 tmp->_next=NULL; 37 } 38 else 39 { 40 node_p cur=head; 41 while(cur->_next) 42 { 43 cur=cur->_next; 44 } 45 cur->_next=tmp; 46 tmp->_next=NULL; 47 } 48 } 49 void push_front(node_p head,data_type data) 50 { 51 node_p tmp=buy_node(data); 52 tmp->_next=head->_next; 53 head->_next=tmp; 54 } 55 int pop_front(node_p head,data_type_p buf) 56 { 57 if(head->_next==NULL) 58 { 59 *buf = -1; 60 return -1; 61 } 62 else 63 { 64 node_p tmp=NULL; 65 tmp=head->_next; 66 *buf=tmp->_data; 67 head->_next=tmp->_next; 68 tmp->_next=NULL; 69 if(tmp) 70 { 71 free(tmp); 72 tmp=NULL; 73 } 74 return 0; 75 } 76 } 77 void show_list(node_p head) 78 { 79 node_p tmp=head->_next; 80 if(tmp) 81 { 82 printf("%d ",tmp->_data); 83 fflush(stdout); 84 tmp=tmp->_next; 85 } 86 printf("\n"); 87 } 88 void *product(void *arg) 89 { 90 pthread_mutex_lock(&lock2); 91 int i=0; 92 while(1) 93 { 94 pthread_mutex_lock(&lock1); 95 printf("product success,produce num:%d,,,val is:%d\n", 96 (int)arg,i); 97 push_back(head,i++); //FIFO 98 //push_front(head,i++); //LIFO 99 pthread_mutex_unlock(&lock1); 100 pthread_cond_signal(&need_product); 101 sleep(2); 102 } 103 pthread_mutex_unlock(&lock2); 104 } 105 void *consumer(void *arg) 106 { 107 pthread_mutex_unlock(&lock3); 108 data_type buf; 109 while(1) 110 { 111 pthread_mutex_lock(&lock1); 112 while(pop_front(head,&buf)==-1) 113 { 114 printf("wait**********\n"); 115 pthread_cond_wait(&need_product,&lock1); 116 } 117 pthread_mutex_unlock(&lock1); 118 printf("consumer success,consumer num:%d,,,val is:%d\n",119 (int)arg,buf); 120 sleep(5); 121 } 122 pthread_mutex_unlock(&lock3); 123 } 124 int main() 125 { 126 init_list(&head); 127 pthread_t tid1,tid2,tid3,tid4; 128 pthread_create(&tid1,NULL,product,(void*)1); 129 pthread_create(&tid2,NULL,product,(void*)1); 130 pthread_create(&tid3,NULL,consumer,(void*)2); 131 pthread_create(&tid4,NULL,consumer,(void*)2); 132 pthread_join(tid1,NULL); 133 pthread_join(tid2,NULL); 134 pthread_join(tid3,NULL); 135 pthread_join(tid4,NULL); 136 return 0; 137 }
FIFO的运行结果:
LIFO的运行结果:
多生产者——多消费者的运行结果: