如何实现一个生产者消费者模型(面试C++)

生产者消费者模型 C++

生产者消费者模型通过一个容器/缓冲区(比如阻塞队列)解决生产者消费者的强耦合问题。生产者和消费者之间通过阻塞队列来进行通讯。生产者产生数据直接扔进缓冲区中,消费者每次取时上锁,避免冲突,取完解锁处理业务逻辑。具体情况,视于队列空和满的条件决定。

实现逻辑

方法:这里采用互斥锁+两个条件变量实现
当队列为空时,消费者线程阻塞,唤醒生成者线程生产;
当队列为满时,生产者线程阻塞,唤醒消费者线程消费。

  • 具体的实现逻辑是构建一个queue来存储生产的数据,阻塞队列不满时可以生产,不空时可以消费。
  • 首先实现构造函数,初始化一个unique_lock供condition_variable使用。
    • 互斥锁构造列表初始化,然后函数体里unlock。
    • 创建两个条件变量,m_cond_Full和m_cond_Empty;
    • m_cond_Full ,超出缓冲区(队列阻塞),上锁m_cond_Full.wait(locker) ,唤醒消费者线程;
      m_cond_Empty,缓冲区为空时,上锁m_cond_Empty.wait(locker),并唤醒生产者线程;
  • 之后就是入和出队列的细节如下,具体看源码。

面试现场测试也没问题~

代码实现

  • thread 消费队列写法
#include <thread>
#include <queue>
#include <iostream>
#include <condition_variable>
//#include<invoke.h>
#include <mutex>

template <typename T> //生产者消费者模式
class Queue
{
public:
    Queue(int maxn = 20) : thread_maxnum(maxn) {}
    //最大线程数量与CPU核数相关

    //生产者
    bool Push(const T &val)
    {
        std::unique_lock<std::mutex> locker(m_mtx);
        if (mq.size() >= thread_maxnum)
        {
            m_cond_Full.wait(locker);   //超出缓冲区加锁
            return false;
        }
        
        m_cond_Empty.notify_all();  //解锁互斥量,唤醒消费者线程
        mq.push(val);
        return true;
    }

    //消费者
    T Pop()
    {
        std::unique_lock<std::mutex> locker(m_mtx);
        while (mq.empty())
        {
            m_cond_Empty.wait(locker);  //缓冲队列为空上锁,阻塞消费者线程
        }

        T val = mq.front();
        mq.pop();
        m_cond_Full.notify_all(); //解锁互斥量,唤醒生产者线程
        return val;
    }

private:
    std::queue<T> mq;
    std::mutex m_mtx;               //互斥锁
    int thread_maxnum;              //最大线程数量,缓冲区数量
    std::condition_variable m_cond_Empty; //条件变量,对应消费者线程
    std::condition_variable m_cond_Full; //条件变量,对应生产者线程
};

void producer(Queue<int> *q)
{
    for (int i = 0; i < 1000; i++)
    {
        if (q->Push(i))
            std::cout << "push: " << i << "\n";
        else
            std::cout << "push failed!\n";
        //std::this_thread::sleep_for(std::chrono::seconds(1000));
    }
}

void consumer(Queue<int> *q)
{
    for (int i = 0; i < 500; i++)
    {
        auto t = q->Pop();
        std::cout << "pop: " << t << "\n";

        //std::this_thread::sleep_for(std::chrono::seconds(500));
    }
}
int main()
{
    Queue<int> q(20);
    std::thread t1(producer, &q);
    std::thread t2(consumer, &q);

    t1.join();
    t2.join();
    return 0;
}

在这里插入图片描述

  • pthread 线程写法
#include <pthread.h>
#include <iostream>
#include <error.h>
using namespace std;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static bool flag = true;
void *producer(void *)
{
    for (int i = 0; i < 60; i++)
    {
        pthread_mutex_lock(&mutex);
        while (!flag)
            pthread_cond_wait(&cond, &mutex);
        cout << "thread1:" << i * 2 << "\n";
        flag = false;
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
    }
}
void *consumer(void *)
{
    for (int i = 0; i < 60; i++)
    {
        pthread_mutex_lock(&mutex);
        while (flag)
            pthread_cond_wait(&cond, &mutex);
        cout << "thread2:" << i * 2 + 1 << "\n";
        flag = true;
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
    }
}
int main()
{
    int iRet = -1;
    pthread_t rask1, rask2;
    iRet = pthread_create(&rask1, NULL, &producer, NULL);
    if (iRet != 0)
    {
        cerr << "producer star error\n";
    }
    iRet = pthread_create(&rask2, NULL, &consumer, NULL);
    if (iRet != 0)
    {
        cerr << "consumer star error\n";
    }

    pthread_join(rask1, NULL);
    pthread_join(rask2, NULL);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Q_Outsider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值