生产者和消费者模型

来源:互联网 发布:代练游戏商场源码 编辑:程序博客网 时间:2024/04/19 19:37

一:条件变量:
我们知道多线程访问时会出现冲突的问题,为了解决这个问题我们引入互斥锁的概念,即多个线程同时访问理解资源时,获得锁多线程可以完成”读-修改-写”操作,然后释放锁给其他线程.没有获得锁的线程只能挂起等待.
与互斥锁不同,条件变量时挂起等待而不是上锁,条件变量用来自动阻塞一个线程,直到某特殊情况的发生,通常条件变量和互斥锁同时使用.
原理:条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程”条件成立”
条件的检测是在互斥锁的保护条件下进行的,如果一个条件为假,一个线程自动阻塞,并释放等待状态的互斥锁,如果一个线程改变了条件,它发关联的条件变量,唤醒一个或多个等待的线程,重新获得互斥锁,然后重新评价条件.如果梁金成共享读写的内存,条件变量可以实现这两个进程间的线程同步
初始化和释放函数:
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
cond一般用宏来进行初始化.

int pthread_cond_destroy(pthread_cond_t *cond)
这里写图片描述
返回值:成功返回0,失败返回错误号
和Mutes的初始化和销毁类似,ptread_cond_init函数初始化一个条件变量,attr参数为NULL,则表示缺省属性,ptread_cond_destory函数销毁一个条件变量,如果条件变量是静态的,可以用宏定义初始化,等同于初始化函数,并且attr参数为NULL;
条件变量还有以下函数:
这里写图片描述
返回值:成功返回0,失败返回错误号
可见,一个条件变量总是和一个Mutex搭配使用,一个线程可以调用pthread_cond_wait在一个条件变量上阻塞等待,这个函数做以下三步操作:
1:释放Mutex
2:阻塞等待
3:当被唤醒时,重新获得Mutex并返回.
pthread_cond_timedwait函数还有一个额外的参数可以设定等待超时,如果达到abstime所指指定的时刻仍然没有别的线程来唤醒当前线程,后返回ETIMEDOUT.一个线程可以调用pthead_cond_signal唤醒在某个Condition Variable上等待的另一个线程,也可以调用pthread_cond_broadcast唤醒在这个Condition Veriable上等待的所有线程.
这里写图片描述
一个线程可以调用pthread_cond_signal唤醒在某个条件变量上等待的另一个线程,也可以调用
pthread_cond_broadcast唤醒在这个条件变量上等待的所有线程.
生产者消费者问题是同步问题中的一种常见情况,生产者消费者问题 .也称有限缓冲问题,是一个多线程同步问题.在实际运行过程中,生产者的主要作用是生成一定数量的数据放到缓冲区中,然后重复此过程,与此同时,消费者也在缓冲区消耗 这些数据.问题的关键是保证生产者不会在缓冲区满时加入数据,消费者不会在缓冲区空时消耗数据.
二:生产者消费者模型
生产者和生产者之间为互斥关系
消费者和消费者之间为互斥关系
生产者与消费者之间既有同步又有互斥关系
这里写图片描述
解耦
假设生产者和消费者分别是两个类,如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合),将来如何是消费者代码发生变化,可能会影响生产者,如果都是依赖这个缓冲区,耦合就会相应的降低
支持并发:
生产者直接调用消费者的某个方法,还有另一个弊端.由于函数调用时同步的,在消费者的方法没有返回之前,生产者只好在一边等待,但是如果消费者处理数据很慢,生产者就会浪费很多时间.
使用生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体,(常见的并发类型有进程和线程两种),生产者生产的数据放到缓冲区,就可以继续生产,基本不依赖消费者的处理速度.
支持忙闲不均
换冲区的另外一个好处是,如果生产的数据快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区,等生产者的生产速度降低,消费者再慢慢处理数据.
基于单链表的生产者消费者模型:

#include<stdio.h>#include<stdlib.h>#include<pthread.h>#include<sys/types.h>#include<sys/stat.h>#include<unistd.h>typedef struct SlistNode{ struct SlistNode*next;    int _data;}Slist;//初始化void Init(Slist*head){    if(head!=NULL)    {        head->next =NULL;        head->_data = 0;    }}Slist*head =NULL;//静态创建static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t producter = PTHREAD_COND_INITIALIZER;//消费者void* consumer(void *arg){    Slist *p = NULL;    while(1)    {        pthread_mutex_lock(&lock);//加锁        while(head ==NULL)        {        //条件不满足,阻塞式等待                     pthread_cond_wait(&producter,&lock);        }        //尾删        p = head;        head =head->next;        p->next = NULL;        pthread_mutex_unlock(&lock);//释放锁        printf("Consumer success :_data is %d\n",p->_data); free(p);p = NULL;    }    return NULL;}//生产者void *product(void *arg){    while(1)    {        sleep(rand()%2);        Slist*p = malloc(sizeof(Slist));        pthread_mutex_lock(&lock);        Init(p);        p->_data = rand()%1000;        //头插        p->next = head;        head= p;        pthread_mutex_unlock(&lock);        printf("call consumer,product success,data is:%d\n",p->_data);        pthread_cond_signal(&producter);    }}int main(){    pthread_t t_product;    pthread_t t_consumer;    pthread_create(&t_product,NULL,product,NULL);//创建线程    pthread_create(&t_consumer,NULL,consumer,NULL);//创建线程    pthread_join(t_product,NULL);//线程等待    pthread_join(t_consumer,NULL);    return 0;}

这里写图片描述

原创粉丝点击