生产者与消费者模型 及 条件变量

生产者与消费者问题 及 条件变量
什么是生产者和消费者模型

生产者,顾名思义就是生产东西的人,而消费者就消费的人。在系统中,假设有一块内存,生产者要向内存中放数据,而消费者要从内存区域中拿数据。这片内存区域可以被所有的线程访问,所以这片内存区域就是临界资源,而在对临界区的访问时,要保证不会出错,必须每次对临界区的访问是互斥的。所以当有许多生产者消费者时,每次只能有一个生产者放数据,也只能有一个消费者拿数据,也就是说该内存区域每次只能被一个线程访问。因此,生产者与生产者之间存在着互斥的关系,而消费者与消费者之间也是互斥的关系,在消费者和生产者之间也存在互斥的关系。除此之外,生产者和消费者之间还有一种关系,我们讲在该内存区域中,生产者向其中放数据,消费者拿数据。但当消费者把其中的数据拿完之后,消费者可能会不断的获得锁释放锁,造成生产者的饥饿问题,所以必须要保持两者之间的同步,让两者之间要按照特定的顺序访问。

当存放的数据为满时,生产者必须等待到可以有一个位置存放数据。当存放数据的位置为空时,消费者必须等待有一个位置已经有数据。而为了解决这些问题要使用条件
变量。

三种关系

  • 消费者与消费者之间 互斥关系
  • 生产者与生产者之间 互斥关系
  • 生产者与消费者之间 互斥同步关系
条件变量

条件变量是为了解决同步的问题。
加入当生产者因为存放数据的区域已经满了,从而要等待有空位时才开始放,但是生产者并不知道何时有空位,因此必须要被通知,可以放数据。条件变量解决了 让生产消费者进行等待,和被唤醒的机制,以此来实现同步。

条件变量中提供了几个函数来完成这些操作

条件变量的初始化
pthread_cond_init(pthread_cond_t *restrict, const pthread_condattr_t *restrict attr)

cond: 要初始化的条件变量
attr:属性设置为空
条件变量的销毁
pthread_cond_destroy(pthread_cond_t *cond)
等待条件变量的满足
pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)

cond:在该条件变量上进行等待
mutex:互斥量

条件变量必须要和互斥锁一起使用,当等待条件变量时,必须先要释放锁(否则会导致,其他的线程无法使用锁,造成死锁),等从等待的条件变量返回时,必须要先获得锁。

唤醒等待
int pthread_cond_broadcast(pthread_cond_t *cond)
//唤醒所有在该条件变量下等待的所有线程
int pthread_cond_signal(pthread_cond_t *cond)
//唤醒该条件变量下的一个线程,等待队列中的第一个线程

pthread_cond_t 和 pthread_mutex_t
都在其内部维持了一个等待队列,来存放等待的线程

为什么在pthread_cond_wait中需要互斥量?
  • 一个线程当在条件不满足时,会陷入等待,而条件变量的等待,必须由其他的线程唤醒,否则会无限期的等待下去。而条件状态不会自己变化,必须由其他线程进行改变,从而使条件满足,并唤醒等待线程。而能被多个线程的看到并访问的为共享变量,对于共享变量的访问,我们必须要使用互斥锁来保护其正确性和安全性。

  • 如果解锁和等待不是一个原子的操作,线程可能会在解完锁,将要进行等待的时候被切换下去,从而可能会错过其他线程发送的唤醒信号,导致该线程无限期阻塞。

  • 因为在等待时会先进行解锁,而在被唤醒后会立即获得锁,这些操作都是原子性的操作

一般的使用规范
pthread_mutex_lock(&lock);
while(条件不满足)  //函数可能会调用失败,所以使用while进行二次检测
    pthread_cond_wait(cond , mutex); 
//操作
pthread_mutex_unlock(&lock);

猜你喜欢

转载自blog.csdn.net/M_jianjianjiao/article/details/84504393
今日推荐