生产消费者(CP)模型

CP模型有三个部分:productor和consumer(由线程组成的功能块)还有一个特定结构的内存空间

以超市为例,超市货物由供应商提供,超市暂时存储货物,消费者可以在超市购买货物。

工作流程;生产者获取数据,生产任务并将任务放到仓库,消费者从仓库获取任务,处理任务


"321"原则

三种关系:

生产者和生产者之间的关系:互斥

消费者和消费者之间的关系:互斥

生产者和消费者之间的关系:互斥,同步(必须生产者生产之后,消费者才能消费,要有顺序)

**二种角色:**生产和消费

**一个交易所:**特定的内存结构空间


优点:

1.支持忙闲不均,如果仓库为满,生产者可以不生产一段时间,消费者可以一直消费

2.生产和消费解耦合,因为有仓库作缓冲

3.提高效率:在生产者获取数据和生产任务的时候,消费者可以处理数据,二者可以同时进行;生产者和消费者是多线程,多个线程同时完成获取数据和处理任务的工作。


代码模拟:

cpp 复制代码
//block_queue.hpp
#include <queue>
#include <mutex>
#include <condition_variable>

#define MAX_CAPACITY 100
template <class T>
class blockqueue
{
public:
    std::queue<T> q;
    int max_capcity = MAX_CAPACITY; // 最大存储数量
    std::mutex pmut;                // 生产者锁
    std::mutex cmut;                // 消费者锁
    std::condition_variable pcon;
    std::condition_variable ccon;
    blockqueue()
    {
    }
    ~blockqueue()
    {
    }

    void push(T &task);
    void pop();
    bool empty();
    size_t size();
    T front();
};

template<class T>
void blockqueue<T>::push(T &task)
{
    q.push(task);
}

template<class T>
void blockqueue<T>::pop()
{
    q.pop();
}

template<class T>
bool blockqueue<T>::empty()
{
    return q.empty();
}

template<class T>
size_t blockqueue<T>::size()
{
    return q.size();
}

template<class T>
T blockqueue<T>::front()
{
    return q.front();
}
cpp 复制代码
//main.cpp
#include <iostream>
#include <ctime>
#include <thread>
#include <unistd.h>
#include "block_queue.hpp"

using namespace std;

void product(blockqueue<string> &bq)
{
    unique_lock<mutex> ul(bq.pmut);
    while (1)
    {
        //获取数据
        int n = rand() % 10000;
        cout << "获取数据:" << to_string(n) << endl;
        sleep(1);
        while (bq.size() >= bq.max_capcity)
        {
            // 不使用if,因为可能造成伪唤醒
            cout << "任务已满,等待" << endl;
            bq.pcon.wait(ul);
        }
        cout << "生成任务" << endl;
        string name = "task" + to_string(n);
        bq.push(name);
        bq.ccon.notify_all();
        sleep(1);
    }
}

void consume(blockqueue<string> &bq)
{
    unique_lock<mutex> ul(bq.cmut);
    while (1)
    {
        while (bq.empty())
        {
            cout << "没有任务,等待" << endl;
            bq.ccon.wait(ul);
        }
        //获取任务
        string name = bq.front();
        cout << "get " << name << endl;
        bq.pop();
        bq.pcon.notify_all();
        //sleep(1);
        //处理任务
        cout << "处理数据中。。。" << endl; 
        //sleep(1);
    }
}

int main()
{
    srand(time(nullptr));
    blockqueue<string> bq;
    //生产者消费者都可以由多个线程组成
    thread p[10];
    for(auto& e:p)
    {
        e = thread(product, ref(bq));
    }
    thread c[5];
    for(auto& e:c)
    {
        e = thread(consume, ref(bq));
    }
    
    sleep(1);
    for(auto& e:p)
    {
        e.join();
    }
    for(auto& e:c)
    {
        e.join();
    }
    

    return 0;
} 

blockqueue<string>对象bq需要在多个线程之间共享,并且需要通过引用传递。使用std::ref可以确保这一点

相关推荐
小林想被监督学习26 分钟前
RabbitMQ 仲裁队列 -- 解决 RabbitMQ 集群数据不同步的问题
linux·分布式·rabbitmq
Icomi_1 小时前
【外文原版书阅读】《机器学习前置知识》1.线性代数的重要性,初识向量以及向量加法
c语言·c++·人工智能·深度学习·神经网络·机器学习·计算机视觉
apocelipes1 小时前
Linux glibc自带哈希表的用例及性能测试
c语言·c++·哈希表·linux编程
xf8079891 小时前
cursor远程调试Ubuntu以及打开Ubuntu里面的项目
linux·运维·ubuntu
dot to one1 小时前
Linux 入门 常用指令 详细版
linux·服务器·centos
Ronin-Lotus2 小时前
上位机知识篇---CMake
c语言·c++·笔记·学习·跨平台·编译·cmake
Golinie2 小时前
记一次Linux共享内存段排除Bug:key值为0x0000000的共享内存段删除不了
linux·bug·共享内存段
狄加山6752 小时前
Linux 基础1
linux·运维·服务器
Once_day2 小时前
Linux-arm(1)ATF启动流程
linux·arm开发
测试冲鸭2 小时前
【可实战】Linux 系统扫盲、 Shell扫盲(如何写一个简单的shell脚本)
linux·运维·arm开发