Linux基于多线程和任务队列实现生产消费模型

news2024/12/23 9:19:16

目录

一、生产者消费者模型

二、代码实现模型

2.1 BlockQueue.hpp

2.2 MainCP.cc

2.3 执行结果

三、效率优势


一、生产者消费者模型

将上述图片逻辑转换成代码逻辑就是,一批线程充当生产者角色,一批线程充当消费者角色,仓库是生产者和消费者获取的公共资源!下面我想用321原则来解释这个模型。

既然是公共资源,那么我们就需要考虑线程安全问题!

3指的是三者之间的关系!当一个生产者向仓库生产资源的时候,消费者不可以进入仓库取资源!同样,当一个生产者向仓库放入资源的时候,其他生产者不能同时也向同一个位置放入资源,也就是说生产者要等上一个生产者走出仓库后进入仓库!同样消费者与消费者也是这样的关系!也就是说生产者与生产者互斥,生产者与消费者互斥,消费者与消费者互斥

当消费者与生产者完成自己的操作后,会提醒对方前来进行对方的操作!也就是说,生产者与消费者同步

2指的是2中角色:生产者和消费者

1指的是存储资源的容器(仓库):一段特定结构的缓冲区(队列、栈、链表)


二、代码实现模型

2.1 BlockQueue.hpp

#pragma once
#include<iostream>
#include<pthread.h>
#include<queue>

template <class T>
class BlockQueue
{
public:
    static const int gmaxcap = 5;

     BlockQueue(const int maxcap = gmaxcap):_capacity(maxcap)
     {
        //初始化
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_pcond,nullptr);
        pthread_cond_init(&_ccond,nullptr);
     }

    void push(const T& in)
    {
        //加锁互斥
        pthread_mutex_lock(&_mutex);

        //细节:为什么这里用while循环判断? 
        //-->有一种可能性,当生产者很多而消费者只有一个,第一次条件满足进入阻塞后,消费者处理了 
        // 一个任务
        //这样就会同时唤醒一批生产者,如果只是if,他们不会再次判断而是直接“同时!”进行后面push的 
        //逻辑!这样不是线程安全的

        while(is_full())
        {
            pthread_cond_wait(&_pcond,&_mutex);
        }
        //进行到这表示一定有空余空间存数据
        _q.push(in);

        //唤醒消费者
        pthread_cond_signal(&_ccond);
        pthread_mutex_unlock(&_mutex);
    }

    void pop(T* out)
    {
        pthread_mutex_lock(&_mutex);
        
        //和上面逻辑一样
        while(is_empty())
        {
            pthread_cond_wait(&_ccond,&_mutex);
        }
        //到这表示一定有数据
        *out = _q.front();
        _q.pop();
        //唤醒生产者
        pthread_cond_signal(&_pcond);
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
    }
private:
    bool is_empty()
    {
        return _q.empty();
    }
    bool is_full()
    {
        return _q.size() == _capacity;
    }
private:
    std::queue<T> _q; //存储任务队列
    int _capacity;
    pthread_mutex_t _mutex; //一把锁 -> 3互斥原则
    pthread_cond_t _pcond; //生产者条件变量
    pthread_cond_t _ccond; //消费者条件变量
};


2.2 MainCP.cc

#include "BlockQueue.hpp"
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <functional>

// 任务对象
class Task
{
public:
    //==typedef
    using func_t = std::function<double(int, int, char)>; 

    Task() {}

    Task(func_t callback, int x = 0, int y = 0, char op = '+') : _x(x), _y(y), _op(op), _callback(callback)
    {
    }
    // 仿函数
    std::string operator()()
    {
        double ret = _callback(_x, _y, _op);
        char buffer[64];
        snprintf(buffer, sizeof buffer, "%d %c %d = %lf", _x, _op, _y, ret);
        return buffer;
    }

private:
    int _x;
    int _y;
    char _op;
    func_t _callback; // 回调函数
};

//处理数据函数
double calculator(int x, int y, char op)
{
    double ret = 0.0;
    switch (op)
    {
    case '+':
        ret = x + y;
        break;
    case '-':
        ret = x - y;
        break;
    case '*':
        ret = x * y;
        break;
    case '/':
        if (y == 0)
            ret = 0;
        else
            ret = (double)x / y;
        break;
    case '%':
        if (y == 0)
            ret = 0;
        else
            ret = x % y;
        break;
    default:
        break;
    }
    return ret;
}

// 生产者任务
void *producer(void *args)
{
    BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);
    while (true)
    {
        // 1.获取数据
        const char *str = "+-*/%";
        int x = rand() % 10 + 1;
        int y = rand() % 5 + 1;
        char op = str[rand() % 5];

        // 2.构建任务对象&传送对于的处理方法
        Task t(calculator, x, y, op);

        // 3.存入队列
        bq->push(t);
        std::cout << "生产任务: " << x << " " << op << " " << y << " = ?" << std::endl;
        sleep(1);
    }
}

// 消费者任务
void *consumer(void *args)
{
    BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);
    while (true)
    {
        Task t;

        // 1.获取任务
        bq->pop(&t);

        // 2.执行仿函数
        std::cout << "消费任务: " << t() << std::endl;
    }
}

int main()
{
    srand((unsigned long)time(nullptr) ^ getpid());

    pthread_t c, p;

    BlockQueue<Task> *bq = new BlockQueue<Task>();
    pthread_create(&c, nullptr, consumer, bq);
    pthread_create(&p, nullptr, producer, bq);

    pthread_join(c, nullptr);
    pthread_join(p, nullptr);
    return 0;
}

2.3 执行结果


三、效率优势

上面的是单个线程,可以拓展到多生产者多消费者!但是我们疑惑的是这个模型在访问资源的时候,都是互斥的!他们只有一个能进入到临界区,这样怎么是高效的?原来这个模型的高效不是在访问临界资源,而是对于每个线程可以独立的准备数据!我们上述实现的数据来源以及数据处理是简单的,但是后面数据可能来源于网络或者磁盘文件,这个过程每个线程都可以同时在线获取或者处理!这个过程如果串行是低效率的,但是多线程可以大大提高IO效率!这就是生产者消费者模型高效的原因!它可以将IO数据分散给多个线程并行处理,极大地提高了效率!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/989867.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpotBugs(是FindBugs的继任者)安装、使用

SpotBugs介绍 SpotBugs和FindBugs的关系 SpotBugs是FindBugs的继任者&#xff0c;从SpotBugs停止的地方继续。 备注&#xff1a;FindBugs项目已经停止了&#xff0c;从2015年发布3.0.1版本以后再没有新的版本。 SpotBugs通过静态分析寻找java代码中的bug&#xff0c;通过发现…

vs2019 c++开发linux应用

VS2019 C的跨平台开发——Linux开发_Mr_L_Y的博客-CSDN博客前言由于前段时间正好买了一个服务器来跑Tensorflow的推理模型&#xff0c;所以借这个机会把Linux的开发也一并补上。先声明我的服务器是Ubuntu16.04&#xff0c;下面文章的内容也是基于Ubuntu16.04的。为什么标题要写…

RDG相关记录

最小模块&#xff1a; 加一个空pass GraphBuilder.AddPass(RDG_EVENT_NAME("TEST"),PassParameters,ERDGPassFlags::Raster,[](FRHICommandList& RHICmdList){}); 注意&#xff1a; PassParameters如果定义错误&#xff0c;不会报错&#xff0c;当时增加pass会…

ABY2.0:更低的通信开销

参考文献&#xff1a; [ABY] Demmler D, Schneider T, Zohner M. ABY-A framework for efficient mixed-protocol secure two-party computation[C]//NDSS. 2015.[ABY3] Mohassel P, Rindal P. ABY3: A mixed protocol framework for machine learning[C]//Proceedings of the…

功能定义-紧急制动系统

功能简介 紧急制动系统的触发过程如上图所示&#xff1a; 安全距离报警&#xff1a;当两车距离较近时&#xff0c;会给予驾驶员相应提示 预报警&#xff1a;当两车存在碰撞风险但风险较低【Danger Level1】时&#xff0c;会给予驾驶员提示【提示相比之前更为明显】 制动预填充&…

【JAVA - List】差集removeAll() 四种方法实现与优化

一、场景&#xff1a; 二、结论&#xff1a; 1. 四种方法耗时 三、代码&#xff1a; 一、场景&#xff1a; 求差集 List1 - Lsit2 二、结论&#xff1a; 1. 四种方法耗时 初始条件方法名方法思路耗时 List1.size319418 List2.size284900 List..removeAll(Lsit2)1036987ms…

Spring初始化项目

1、官网用法 访问地址&#xff1a;https://start.spring.io idea配置&#xff1a;https://start.spring.io 2、阿里巴巴加速 访问地址&#xff1a;https://start.aliyun.com/bootstrap.html idea配置&#xff1a;https://start.aliyun.com 3、区别 官网阿里巴巴版本最新稍…

MySQL知识笔记——初级基础(实施工程师和DBA工作笔记)

老生长谈&#xff0c;MySQL具有开源、支持多语言、性能好、安全性高的特点&#xff0c;广受业界欢迎。 在数据爆炸式增长的年代&#xff0c;掌握一种数据库能够更好的提升自己的业务能力&#xff08;实施工程师&#xff09;。 此系列将会记录我学习和进阶SQL路上的知识&#xf…

无需编程经验,也能制作租车预约微信小程序,快速上手

现在&#xff0c;制作租车预约微信小程序不再需要编程经验&#xff0c;只需几个简单的步骤&#xff0c;您就可以拥有自己的租车预约微信小程序。在本文中&#xff0c;我们将介绍如何利用乔拓云网后台来制作租车预约微信小程序&#xff0c;并实现您所需的功能。 首先&#xff0c…

【Spring AOP】什么是 AOP ?

目录 &#x1f957;1 AOP 的思想 &#x1f35a;2 AOP 的组成 &#x1f95a;2.1 切面 &#x1f359;3 AOP 的实现 &#x1f364;3.1 添加 Spring AOP 依赖 &#x1f96b;3.2 定义切面 &#x1f363;3.3 定义切点 &#x1f373;3.4 实现通知 &#x1f354;4 AOP 实现的一个例子 1…

ucosii任务切换及任务同步

任务的切换 一、 运行态&#xff1a;占用CPU 二、 等待&#xff1a;调用Pend或延时函数后&#xff0c;释放CUP使用权。 三、 就绪&#xff1a;Pend条件满足&#xff08;消息到来、等待超时&#xff09;&#xff0c;延时时间完毕后&#xff08;由等待进入就绪&#xff09; 四、 …

好奇!为什么很少看到女项目经理?

最近被刚进公司的新人问到&#xff0c;在项目管理领域&#xff0c;为什么女性项目经理的数量相对较少。一时之间我也有些茫然&#xff0c;下了班总结一下&#xff0c;跟大家探讨探讨。 一、职业选择的局限性 其实大多数时候&#xff0c;出现和性别有关的问题时&#xff0c;都是…

基于SSM的社区管理与服务系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

uniapp打包微信小程序。报错:https://api.weixin.qq.com 不在以下 request 合法域名列表

场景&#xff1a;在进行打包上传测试时&#xff0c;发现登录失效&#xff0c;但在测试中【勾选不效应合法域名】就可以。 出现原因&#xff1a;我在获取到用户code后&#xff0c;直接使用调用官方接口换取openid 解决方案&#xff1a; 可以把code带给后端&#xff0c;让他们返…

华为Mate 60和iPhone 15选哪个?

最近也有很多朋友问我这个问题来着&#xff0c;首先两款手机定位都是高端机&#xff0c;性能和体验各有千秋&#xff0c;各自有自己的铁杆粉。 但是让人意想不到的是华为mate60近日在海外越来越受欢迎和追捧&#xff0c;甚至是引起了不少人的抢购&#xff0c;外观设计和…

记一次诡异的Cannot find declaration to go to,Cannot resolve method

记一次诡异的 Cannot find declaration to go to&#xff0c; Cannot resolve method getOnExpressions in Join 对于项目中通常问题&#xff0c;清除缓存&#xff0c;重启idea&#xff0c;或者仔细检查语法通常都能解决问题&#xff0c;但是这次却失效了&#xff0c;以下是原…

移动app、接口、web自动化测试区别

先说说WEB的UI自动化测试&#xff1a;很多人在说自动化测试的时候&#xff0c;基本上现在指的是WEB的UI自动化测试&#xff0c;但其实这是不对的&#xff0c;自动化测试包含了很多开发的技术&#xff0c;不只是界面上的自动化测试。WEB的UI自动化测试只是其中的一种&#xff0c…

统一潮流控制器 (UPFC) 的应用,以增强电力系统中的电压稳定性(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

JavaScript事件处理

表单事件 表单事件在HTML表单中触发 (适用于所有 HTML 元素&#xff0c;但该HTML元素需在form表单内)&#xff1a; 案例演示1&#xff1a;当文本框获取焦点&#xff0c;文本框背景为红色&#xff0c;当文本框失去焦点&#xff0c;文本框背景为黄色 <!DOCTYPE html> <…

双翌保养码使用指南方法(一)

保养码使用指南一 为了确保软件的正常运行和有效使用&#xff0c;正确地使用保养码是至关重要的。以下是保养码使用的简单指南&#xff0c;以帮助您进行正确的操作。 1. 打开软件入口&#xff1a;首先&#xff0c;在您的电脑上打开文件夹&#xff0c;并找到s-y softactive tool…