生产者消费者模型中有两种角色, 一种是生产者, 一种是消费者.(这不是废话么)这个模型一般是配合多线程环境使用的
生产者线程负责生产资源, 消费者线程负责使用(消费)资源. 由于资源是双方共享的临界资源, 那么在多线程的环境下就必然会涉及到线程安全的问题, 因此模型必须满足如下的要求:
为实现如上要求常需要使用条件变量(cond)和锁(mutex):
Linux下使用条件变量需要包含一个头文件
, 由于生产者和消费者是两种角色, 我们需要使用两个条件变量来分别管理这些线程.
比如说
pthread_cond_t producer_cond;
pthread_cond_t consumer_cond;
条件变量在使用前需要使用pthread_cond_init函数初始化
函数原型
int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex);
函数本身是不需要锁的, 参数列表中的mutex是函数的设计者为了方便用户的使用而添加的
调用了pthread_cond_wait函数的线程, 首先会释放锁资源, 然后被放入PCB等待队列中挂起, 直到被别的进程唤醒(或者时间到了), 唤醒之后会去竞争锁资源. 也就是说, pthread_cond_wait函数封装了释放锁资源、挂起等待、获取锁资源这三步
在生产者消费者模型当中, 资源满时生产者调用pthread_cond_wait, 资源空时消费者调用pthread_cond_wait, 那么代码逻辑要怎么写呢?
比如说生产者
if(Full()){
pthread_cond_wait(&producer_cond, &lock);
}
我们来看看这样写有什么问题.假设 线程A 线程B 都是生产者线程, 某一时刻两线程被同时唤醒, 于是两者开始争夺锁资源, 假设线程B抢到了锁, 线程A就卡在了pthread_mutex_lock(&lock)函数中, 然后当线程B生产完释放锁后, 线程A抢到了锁, 并开始生产资源, 然而此时由于线程B已经生产了一个资源, 资源已经满了, 线程A实际上不应该生产资源, 而是继续等待.
因此代码应该这样改:
while(Full()){
pthread_cond_wait(&producer_cond, &lock);
}
这样, 每个生产者线程在每次抢到锁之后都要去判断临界资源是否已满, 从而保证了资源访问的合理性