操作系统经典同步问题-生产者与消费者

该问题也叫有限缓冲问题,注意点:

  1. 一般当缓冲区满时,生产者进入睡眠,消费者消费数据后唤醒生产者。
  2. 缓冲区空时消费者进入睡眠,生产者生产数据后唤醒消费者。
  3. 一个线程进行生产或消费时,其余线程不能再进行生产或消费等操作,即保持线程间的同步。

处理不当便会造成生产者、消费者均进入睡眠状态,即死锁状态。

#include<iostream>
#include<thread>
#include<queue>
#include<mutex>
#include<condition_variable>
 
using namespace std;
mutex mu;
condition_variable notEmpty; // 作为通知消费者可以消费的条件变量
condition_variable notFull;  // 作为通知生产者可以生产的条件变量
queue<int> myQue;
bool isNotFull = true;
// 生产者
void Producer() 
{
    while (true) {
        unique_lock<mutex> myLock(mu);
        // 1.isNotFull满足时,则上锁继续往下执行;不满足时则解锁,睡眠
        // 2.睡眠中收到notify_one的信号,再次判断isNotFull,满足则上锁继续往下执行,否则解锁,睡眠
        notFull.wait(myLock, [](){return isNotFull;}); 
        myQue.push(1);
        if (myQue.size() == 10) {
            isNotFull = false;
        }
        myLock.unlock();
        notEmpty.notify_one(); // 唤醒消费者线程
    }
}
 
// 消费者
void Consumer()
{
    while (true) {
        unique_lock<mutex> myLock(mu);
        notEmpty.wait(myLock, [](){return !myQue.empty();});
        cout << myQue.front() << endl;
        myQue.pop();
        isNotFull = true;
        myLock.unlock();
        notFull.notify_one(); // 唤醒生产者线程
    }
}
 
int main(int args, char** argu)
{
    thread t1(Producer);
    thread t2(Consumer);
    t1.join();
    t2.join();
    return 0;
}

针对condition_variable再说明一下:

  1. wait()用来等一个东西,如果第二个参数lambda表达式返回值是true,那wait()直接返回;
  2. 如果第二个参数lambda表达式返回值是false,那么wait()将解锁互斥量,并堵塞到本行。那堵要到什么时候力止呢?堵塞到其他某个线程调用notify_one()成员函数为止。
  3. 如果wait0没有第二个参数,那么就跟第二个参数lambde表达式返回false效果一样,wait0将解锁互斥量,并堵塞到本行,堵塞到其他某个线程调用notify_one()成员函数为止。
  4. 当其他线程用notify_one()将本wait()(原来是睡着/堵塞)的状态唤醒后, wait开始恢复干活了,不断尝试重新获取互斥量锁,如果获取不到,那么流程卡在wait这里等着获取,如果获取到了,那么wait就走下来了,继续执行。
     
发布了42 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/ustczhng2012/article/details/103038864