条件变量(condition variable)

线程间的同步与互斥技术,主要以互斥锁和条件变量为主,条件变量和互斥所的配合使用可以很好的处理对于条件等待的线程间的同步问题。举个例子:消费者和生产者问题。

消费者与生产者最基本的关系是服务与被服务的关系,但是在线程同步与互斥中强调的是两者访问资源的关系。首先生产与消费的关系为:同步与互斥,生产与生产的关系为:互斥,消费与消费的关系为:互斥。所以维护这三种关系的有两类人:生产者与消费者。并且生产数据与消费数据必须有场所。

所以将其简述为三种关系两类人一个场所(当然这里的场所并不是只能有一个,可以是多样的)。

介绍条件变量的几个函数:

1.定义一个条件变量

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

2.初始化条件变量(当定义没初始化时)

int pthread_cond_init(pthread_cond_t *restrict cond,

const pthread_condattr_t *restrict attr);

3.销毁条件变量

int pthread_cond_destroy(pthread_cond_t *cond)

举一个单个消费者与单个生产者问题:

1#include<stdio.h>2#include<pthread.h>3#include<assert.h>4#include<stdlib.h>5pthread_cond_tcond;6typedefintdata_type;7pthread_mutex_tlock=PTHREAD_MUTEX_INITIALIZER;8voidpush_node(data_typedata);9intpop_node();10void*producter(void*arg)11{12data_typei=0;13while(1)14{15pthread_mutex_lock(&lock);16i++;17push_node(i);18sleep(2);19pthread_mutex_unlock(&lock);20printf("productdone......\n");21sleep(2);22pthread_cond_signal(&cond);23sleep(2);25}2627}28void*consumer(void*arg)29{30data_typeres=-1;31while(1)32{33pthread_mutex_lock(&lock);34while(-1==pop_node(&res))35{36pthread_cond_wait(&cond,&lock);37}38res=pop_node(&res);39printf("consumerdata:%d\n",res);40sleep(2);41pthread_mutex_unlock(&lock);44pthread_cond_signal(&cond);45sleep(2);4647}4849}5051typedefstruct_node52{53data_type_data;54struct_node*_next;55}node,*node_p,**node_pp;5657node_phead=NULL;58staticnode_pbuy_node(data_typedata)59{60node_ptmp=malloc(sizeof(node));61if(tmp==NULL)62{63printf("mallocfailed\n");6465}66tmp->_data=data;67tmp->_next=NULL;68returntmp;69}71voidinit_list(node_ppphead)72{73*phead=buy_node(0);74}7576voidpush_node(data_typedata)77{7879if(head->_next==NULL)80head->_next=buy_node(data);81else{82node_ptmp=buy_node(data);83tmp->_next=head->_next;84head->_next=tmp;85}86}878889intpop_node(data_type*data)90{data_typeret=0;9192if(head->_next==NULL)93return*data;else{95node_ptmp=head->_next;96head->_next=tmp->_next;97*data=tmp->_data;98free(tmp);99}100return*data;101}102intmain()103{104105init_list(&head);106pthread_cond_init(&cond,NULL);107pthread_mutex_init(&lock,NULL);108pthread_ttid1,tid2;109pthread_create(&tid1,NULL,producter,NULL);110pthread_create(&tid2,NULL,consumer,NULL);111pthread_join(tid1,NULL);112pthread_join(tid2,NULL);113pthread_cond_destroy(&cond);114pthread_mutex_destroy(&lock);115return0;}

运行结果:


结果分析:

生产者生产出一个数据之后消费者才能消费,当链表里没有数据时,消费者就等待对应的条件变量和锁,直到他们被释放消费者才能进去消费。

扩展:多消费者与多生产者问题

10pthread_mutex_tplock=PTHREAD_MUTEX_INITIALIZER;11pthread_mutex_tconlock=PTHREAD_MUTEX_INITIALIZER;12voidpush_node(data_typedata);13intpop_node();14void*producter(void*arg)15{16data_typei=0;17while(1)18{sem_wait(&sem_product);19pthread_mutex_lock(&plock);20i++;21push_node(i);22sleep(2);23pthread_mutex_unlock(&plock);24sem_post(&sem_consume);25printf("productdone......\n");26sleep(2);27pthread_cond_signal(&cond);28sleep(2);2930}3132}33void*consumer(void*arg)34{35data_typeres=-1;36while(1)37{38sem_wait(&sem_consume);39pthread_mutex_lock(&conlock);40while(-1==pop_node(&res))41{42pthread_cond_wait(&cond,&plock);43}44res=pop_node(&res);45printf("consumerdata:%d\n",res);46sleep(2);47pthread_mutex_unlock(&conlock);4849sem_post(&sem_product);5051pthread_cond_signal(&cond);5253sleep(2);5455}

再来引入一概念:POSIX版本下的信号量-semaphore

这个信号量也相当于一个计数器,记录当前资源的数量。其进行的是PV 操作。

有关于信号量的函数:

sem_t sema;//定义一个信号量

int sem_init(sem_t *sem, int pshared, unsigned int value);//初始化信号量

int sem_destroy(sem_t *sem);//销毁信号量

例子:

定义一个环形buf让生产者生产数据,消费者消费数据,生产者不能将消费者套圈,消费者也不能超过消费者。

1 #include<stdio.h>

2 #include<semaphore.h>

3 #include<pthread.h>

4 #define _SIZE_ 20

5 sem_t blank;

6 sem_t data;

7 int buf[_SIZE_];

8 void *product(void*arg)

9 {

10 int index=0;

11 int count=0;

12 while(1)

13 {

14 sem_wait(&blank);//申请格子

15 buf[index]=count++;

16 sem_post(&data);//释放数据

17 sleep(10);

18 index++;

19 index%=_SIZE_;

20 }

}

25 void* consume(void* arg)

26 {

27 int index=0;

28 int count=0;

29 while(1)

30 {

31 sem_wait(&data);//申请数据

32 count=buf[index];

33 printf("consume data: %d\n",count);

34 sem_post(&blank);//释放格子

35 sleep(5);

36 index++;

37 index%=_SIZE_;

38 }

41 }

42 int main()

43 {

44 pthread_t tid1,tid2;

45 pthread_create(&tid1,NULL,product,NULL);

46 pthread_create(&tid2,NULL,consume,NULL);

47 sem_init(&blank,0,_SIZE_);//有20个格子的数量

48 sem_init(&data,0,0);

49 pthread_join(tid1,NULL);

50 pthread_join(tid2,NULL);

51 sem_destroy(&blank);

52 sem_destroy(&data);

53 return 0;

54 }

程序分析: 这个程序就满足上述条件,生产者不会将消费者套圈,因为信号量在记录格子的数量,同样的消费者也不会超过生产者,因为消费的时候数据在减少。