条件变量
为什么要有条件变量??
当一个线程互斥的访问某个变量时,这个线程在其他线程改变状态之前什么也不能干,只能等待
比如说,一个线程访问队列时,发现队列为空,那么就会一直等待,直到有节点添入该队列,这个时候就应该使用条件变量,告诉该线程你可以去做其他的事情不用一直等,如果有你想要的我会通知你
1. pthread_cond_t cond;------------------------创建条件变量
2. pthread_cond_init(&cond, NULL);-------------初始化 条件变量
3. pthread_cond_wait(&cond, &mutex);-----------在cond这个条件变量上等待,
// 阻塞,将mutex置成1,
// 返回,将mutex恢复成原样
4. pthread_cond_signal(&cond);-----------------当有资源可用时传回一个信号去唤醒等待
5. pthread_cond_destroy(&cond);----------------销毁条件变量
wait为什么要有互斥量?
在某些情况下,如果某个条件变量一直得不到满足,那么该条件变量就会一直等待,这时候需要有一个线程来改变共享变量,当条件变量得到满足时,还需要通知等待在条件变量上的线程,告诉它你要的资源已经有了,快来访问吧~
使用规范: { pthread_mutex_lock(&mutex); while ( 条件不满足 ) // while 防止假唤醒 pthread_cond_wait(&cond, &mutex); 修改条件 pthread_mutex_unlock(&mutex); } //给条件变量发送信号 { pthread_mutex_lock(&mutex); pthread_cond_signal(&cond); // 唤醒等待,如果没有线程等在wait,signal就丢失 pthread_mutex_unlock(&mutex); }wait和unlock必须是原子操作,否则可能会导致wait错过原本应该等待的信号,那么在等待的线程就会阻塞。
基于条件变量和互斥量编写的生产者消费者模型(使用链表编写)
//////////////////////////////////////////////////////////我是分割线////////////////////////////////////////////////////// 1#include<stdio.h> 2 #include<pthread.h> 3 #include<stdlib.h> 5 typedef struct _Node{ 6 int data; 7 struct _Node *next; 8 }node_t,*node_p,**node_pp; 9 //加锁 10 node_p head; --------------------------------------------------------------------------------------------------------------------------------------- 12 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//条件变量 13 14 static node_p alloc_node(int _d,node_p _n) 15 { 16 node_p tmp = (node_p)malloc(sizeof(node_t)); 17 if(!tmp) 18 { 19 perror("malloc"); 20 exit(1); 21 } 22 23 tmp->data = _d; 24 tmp->next = _n; 25 return tmp; 26 } --------------------------------------------------------------------------------------------------------------------------------------- 27static void freeNode(node_p tmp) 28 { 29 if(tmp) 30 { 31 free(tmp); 32 } 33 } --------------------------------------------------------------------------------------------------------------------------------------- 34 int isEmpty(node_p _h) 35 { 36 return _h->next==NULL?1:0; 37 } --------------------------------------------------------------------------------------------------------------------------------------- 38 void initList(node_pp _hp) 39 { 40 *_hp = alloc_node(0,NULL); 41 } --------------------------------------------------------------------------------------------------------------------------------------- 43 void pushHead(node_p _h,int _d) 44 { 45 node_p tmp = alloc_node(_d,NULL); 46 47 tmp->next = _h->next; 48 _h->next = tmp; 49 } --------------------------------------------------------------------------------------------------------------------------------------- 51void popHead(node_p _h,int * _outdata) 52 { 53 if(!isEmpty(_h)) 54 { 55 node_p tmp = _h->next; 56 _h->next = tmp->next; 57 *_outdata = tmp->data; 58 freeNode(tmp); 59 tmp = NULL; 60 } 61 } --------------------------------------------------------------------------------------------------------------------------------------- 62 void destroyList(node_p _h) 63 { 64 int data; 65 while(!isEmpty(_h)) 66 { 67 popHead(_h,&data); 68 } 69 freeNode(_h);//释放最后一个 70 } --------------------------------------------------------------------------------------------------------------------------------------- 71void showList(node_p _h) 72 { 73 node_p start = _h->next; 74 while(start) 75 { 76 printf("%d ",start->data); 77 start = start->next; 78 } 79 printf("\n"); 80 } -----------------------------------------------------------消费者---------------------------------------------------------------------- 82void* consume(void* arg) 83 { 84 pthread_mutex_t *lockp = (pthread_mutex_t*)arg; 85 int data = 0; 86 while(1) 87 { 88 //data = -1; 89 pthread_mutex_lock(lockp); 90 //互斥性检测 91 while(isEmpty(head)) 92 { 93 pthread_cond_wait(&cond, lockp);//保证当前进程休眠,所以要释放锁,休眠之后还要能被唤醒 94 } 95 popHead(head,&data); 96 97 printf("consumer done ,%d \n",data); 98 pthread_mutex_unlock(lockp); 99 } 100 } --------------------------------------------------------------------生产者------------------------------------------------------ void* produce(void* arg) 102 { 103 pthread_mutex_t *lockp = (pthread_mutex_t*)arg; 104 int data = 0; 105 while(1) 106 { 107 pthread_mutex_lock(lockp); 108 data = rand()%1234; 109 110 pushHead(head,data); 111 printf("producer done ,%d \n",data); 112 pthread_mutex_unlock(lockp); 113 pthread_cond_signal(&cond); 114 sleep(1); 115 } 116 } ----------------------------------------------------------------------主函数------------------------------------------------------ int main() { pthread_mutex_t lock ; pthread_mutex_init(&lock,NULL); initList(&head); pthread_create(&consumer,NULL,consume,(pthread_mutex_t*)&lock); pthread_create(&producer,NULL,produce,(pthread_mutex_t*)&lock); pthread_join(consumer,NULL); pthread_join(producer,NULL); destroyList(head); pthread_mutex_destroy(&lock); pthread_cond_destroy(&cond); }
运行结果:
Posix信号量
该信号量与SystemV信号量的作用类似,但该信号量用于线程间同步
sem_t sem;
初始化信号量
int sem_init(sem_t *sem,
int pshared, // 0 表示本进程内多个线程间的同步互斥
unsigned int value) // 设置初值
// 销毁信号量
int sem_destroy(sem_t *sem);
等待信号量(类似于P操作)
int sem_wait(sem_t *sem);-----------------将信号量的值减一
释放信号量(类似于V操作)
int sem_post(sem_t *sem);-----------------将信号量的值加一