基于BlockQueue的生产消费模型及Linux中的信号量

news2024/11/28 4:27:35

 基于BlockQueue的生产消费模型

Task.hpp

#pragma once

#include<cstdio>
#include<iostream>
#include<string>
#include<functional>

using namespace std;
class CalTask
{
    using func_t=function<int(int,int,char)>;
    //typedef function<int(int,int)> func_t;
public:
    CalTask()
    {}
    CalTask(int x,int y,char op,func_t func):_x(x),_y(y),_op(op),_callback(func)
    {}
    string operator()()
    {
        int result=_callback(_x,_y,_op);
        //构建结构字符串
        char buffer[1024];
        snprintf(buffer,sizeof buffer,"%d %c %d = %d ",_x,_op,_y,result);
        return buffer;
    }
    string toTaskString()
    {
        char buffer[1024];
        snprintf(buffer,sizeof buffer,"%d %c %d = ? ",_x,_op,_y);
        return buffer;
    }
private:
    int _x;
    int _y;
    char _op;
    func_t _callback;
};

int mymath(int x,int y,char op)
{
    int result=0;
    switch(op)
    {
        case '+':
            result=x+y;
        break;
        case '-':
            result=x-y;
        break;
        case '*':
            result=x*y;
        break;
        case '/':
        {
            if(y==0)
            {
                cerr<<"div zero error!!!"<<endl;
                result=-1;
            }
            else
                result=x/y;
        }
        break;
        case '%':
        {
            if(y==0)
            {
                cerr<<"mod zero error!!!"<<endl;
                result=-1;
            }
            else
                result=x%y;
        }          
        break;
        default:
        break;
    }
    return result;
}
class SaveTask
{
    typedef function<void(const string&)> func_t;
public:
    SaveTask()
    {}
    SaveTask(const string &message,func_t func)
    :_message(message),_func(func)
    {}
    void operator()()
    {
        _func(_message);
    }
private:
    string _message;
    func_t _func;
};
void Save(const string& message)
{
    const string target="./log.txt";
    FILE* fp=fopen(target.c_str(),"a+");
    if(!fp)
    {
        cerr<<" fopen error "<<endl;
        return;
    } 
    fputs(message.c_str(),fp);
    fputs("\n",fp);
    
    fclose(fp);
}

Block.hpp

#pragma once

#include<iostream>
#include<queue>
#include<pthread.h>
#include<unistd.h>

using namespace std;
static const int gmaxcap=5;
template<class T>
class BlockQueue
{
public:
    
    BlockQueue(const int& maxcap=gmaxcap)
        :_maxcap(maxcap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_pcond,nullptr);
        pthread_cond_init(&_ccond,nullptr);
    }
    void push(const T& in)//输入型参数,const &
    {
        pthread_mutex_lock(&_mutex);
        //1.判断
        while(is_full())//防止向队列中多push内容->提高代码健壮性
        {//生产条件不满足无法生产,需要生产者等待
        //临界区:
        //pthread_cond_wait   第二个参数必须为我们正在使用的互斥锁!!!
        //1.pthread_cond_wait:该函数在调用的时候,会以原子性的方式将锁释放,并将自己挂起
        //2.pthread_cond_wait:该函数在被唤醒返回的时候,会自动重新获取当时传入的锁
            pthread_cond_wait(&_pcond,&_mutex);
        }
        _q.push(in);
        //pthread_cond_signal即可在临界区内也可在临界区外
        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()==_maxcap;
    }
    queue<T> _q;
    int _maxcap;//队列中元素的上限
    pthread_mutex_t _mutex;
    pthread_cond_t _pcond;//生产者对应的条件变量
    pthread_cond_t _ccond;//消费者对应的条件变量
}; 

Main.cc

#include<time.h>
#include<cstring>
#include<sys/types.h>
#include"BlockQueue.hpp"
#include"Task.hpp"

const string oper="+-*/%";

template<class C,class S>
class BlockQueues
{
public:
    BlockQueue<C> *c_bq;
    BlockQueue<S> *s_bq;
};
void* productor(void *bqs_)
{
    //BlockQueue<Task>* bq=static_cast<BlockQueue<Task>*>(bq_);
    BlockQueue<CalTask>* bq= (static_cast<BlockQueues<CalTask,SaveTask>*>(bqs_))->c_bq;

    while(true)
    {
        //生产活动-x先用随机数构建数据
        int x=rand()%10+1;
        int y=rand()%5;
        int operCode=rand()%oper.size();
        CalTask t(x,y,oper[operCode],mymath);
        bq->push(t);
        cout<<"productor thread,生产数据: "<<t.toTaskString()<<endl;
        sleep(1);
    }
    return nullptr;
}
void *consumer(void* bqs_)
{
    //BlockQueue<Task>* bq=static_cast<BlockQueue<Task>*>(bq_);
    BlockQueue<CalTask>* bq= (static_cast<BlockQueues<CalTask,SaveTask>*>(bqs_))->c_bq;
    BlockQueue<SaveTask>* save_bq= (static_cast<BlockQueues<CalTask,SaveTask>*>(bqs_))->s_bq;
    
    while(true)
    {
        //消费活动
        CalTask t;
        bq->pop(&t);
        string result=t();
        cout<<"消费任务: "<<result<<endl;
        
        // SaveTask save(result,Save);
        // save_bq->push(save);
        // cout<<"consumer thread,推送保存任务完成..."<<endl;

    }
    return nullptr;
}

void* saver(void* bqs_)
{
    BlockQueue<SaveTask>* save_bq= (static_cast<BlockQueues<CalTask,SaveTask>*>(bqs_))->s_bq;

    while(true)
    {
        SaveTask t;
        save_bq->pop(&t);
        t();
        cout<<"保存任务完成..."<<endl;
    }
}
int main()
{
    srand((unsigned long)time(nullptr));
    BlockQueues<CalTask,SaveTask> bqs;
    bqs.c_bq=new BlockQueue<CalTask>();
    bqs.s_bq=new BlockQueue<SaveTask>();

    pthread_t c,p,s;
    pthread_create(&c,nullptr,consumer,&bqs);
    pthread_create(&p,nullptr,productor,&bqs);
    // pthread_create(&s,nullptr,saver,&bqs);
    
    pthread_join(c,nullptr);
    pthread_join(p,nullptr);
    // pthread_join(s,nullptr);
    
    delete bqs.c_bq;
    delete bqs.s_bq;
    return 0;
}

POSIX信号量

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于 线程间同步。 

        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);

该段代码涉及到对临界资源的访问:

1.一个线程,在操作临界资源的时候,临界资源必须是满足条件的!!!

2.公共资源是否满足生产或消费条件【我们在访问之前无法得知】

3.只能先加锁,在检测,在操作,在解锁

只要对资源进行整体加锁,就默认对资源整体使用,但是实际情况可能是一份公共资源允许同时访问不同区域。

什么事信号量???

a.信号量本质是一个计数器。->用来衡量有多少临界资源。

b.只要拥有信号量,就在未来一定能够拥有临界资源的一部分。

申请信号量的本质:对临界资源中特定小块资源的预定机制。

通过信号量可以在访问临界资源之前,提前知道临界资源的使用情况。

信号量的核心操作:PV原语

sudo find ../../ -name Thread.hpp
cp ../../lesson32/Thread.hpp .

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

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

相关文章

OW-VISCap——开放世界视频实例分割方法研究

概述 论文地址&#xff1a;https://arxiv.org/pdf/2404.03657 本文提出了一种名为 OW-VISCap&#xff08;开放世界视频实例分割和字幕&#xff09;的方法。其三大贡献是 开放世界对象查询&#xff1a;除了已知对象查询外&#xff0c;还引入了开放世界对象查询&#xff0c;以发…

python爬虫521

爬虫521 记录 记录 最近想学爬虫&#xff0c;尝试爬取自己账号下的文章标题做个词云 csdn有反爬机制 原理我就不说啦 大家都写了 看到大家结果是加cookie 但是我加了还是521报错 尝试再加了referer 就成功了(╹▽╹) import matplotlib import requests from wordcloud impor…

第2章-03-HTTP协议,POST与GET等请求方式

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年CSDN全站百大博主。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于专栏:Web爬虫入门与实战精讲,后续完整更新内容如下。 文章…

揭秘移动IP:为何定位精度多停留在城市级?

随着电子信息技术的日新月异&#xff0c;移动网络已深度融入我们的日常生活&#xff0c;从2G的初步尝试到5G的飞跃&#xff0c;不仅数据传输速度实现了质的飞跃&#xff0c;更催生了丰富多样的移动应用场景与功能。在这一变革浪潮中&#xff0c;移动IP&#xff08;Mobile IP&am…

再见百度网盘,我有ZFile了!!【送源码】

项目简介 ZFile是一款强大的在线网盘管理系统&#xff0c;专为个人用户设计&#xff0c;能够将不同类型的存储资源统一在一个简洁易用的界面中进行管理和访问。通过ZFile&#xff0c;用户不再需要记住并登录多个云存储平台&#xff0c;所有的文件管理操作都可以在一个地方完成&…

Tomcat:Web 领域的闪耀明珠,魅力何在?

一、Web技术 HTTP 协议&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是互联网上应用最为广泛的一种网络协议。它的主要作用是在客户端和服务器之间传输超文本数据&#xff0c;如网页、图片、视频等。 HTTP 协议的特点 无状态性 HTTP 协议是…

【数学建模】优化模型——两辆平板车装货问题

问题描述 包装箱规格&#xff1a;共有七种规格的包装箱&#xff0c;每种包装箱的厚度&#xff08;t&#xff09;和重量&#xff08;w&#xff09;不同。表中列出了每种包装箱的厚度、重量及数量。 平板车限制&#xff1a; 每辆平板车的可用装载长度为10.2米&#xff08;1020厘…

《QT从基础到进阶·七十三》Qt+C++开发一个python编译器,能够编写,运行python程序

1、概述 源码放在文章末尾 该项目利用QtC实现了一个简易的python编译器&#xff0c;类似pycharm或vsCode这样的编译器&#xff0c;该python编译器支持如下功能&#xff1a; &#xff08;1&#xff09;支持编写python程序 &#xff08;2&#xff09;编写代码时有代码补全提示 &…

写给大数据开发:如何优化临时数据查询流程

你是否曾因为频繁的临时数据查询请求而感到烦恼&#xff1f;这些看似简单的任务是否正在蚕食你的宝贵时间&#xff0c;影响你的主要工作&#xff1f;如果是&#xff0c;那么这篇文章正是为你而写。 目录 引言&#xff1a;数据开发者的困境问题剖析&#xff1a;临时数据查询的…

MKS电源GMW-25RF Plasma Generator手侧

MKS电源GMW-25RF Plasma Generator手侧

C语言基础(八)

1、标准库函数&#xff1a; 测试代码1&#xff1a; #include <stdio.h> // 标准库函数头文件导入 // 自定义函数 int add(int a, int b) { return a b; } // 声明回调函数类型 typedef void (*Callback)(int); // 调用回调函数的函数 void process(Callb…

网络编程第三天

服务器&#xff1a; #include<sys/types.h> // 支持套接字地址结构 #include <sys/socket.h> // 提供套接字API #include <netinet/in.h> // 定义IP地址结构体 #include <string.h> // 提供字符串操作函数 #include <stdio.h> // 提供标准I/O操…

宠物空气净化器哪款能吸毛?希喂、米家宠物空气净化器测评分享

养猫最令人困扰的&#xff0c;就是掉毛与难以彻底消除的异味&#xff0c;这两个问题就成了养猫生活中的一大挑战。每当换季或是猫咪自我梳理时&#xff0c;家中便被一层细腻的绒毛覆盖&#xff0c;从地板到沙发&#xff0c;从床单到衣物&#xff0c;甚至是空气中都漂浮着细小的…

Dockerfile中CMD和ENTRYPOINT区别以及结合使用

1. 简述 在Dockerfile中,CMD和ENTRYPOINT都是用于指定容器启动时要运行的命令,但它们在使用方式和目的上有所不同。 下面将分别解释这两个指令的含义,并通过示例说明它们之间的区别,以及常见的结合使用案例。 Dockerfile制作镜像流程图: 2. CMD CMD指令用于指定容器启…

RocketMQ环境搭建(宝塔)

文章目录 1.介绍2.RocketMQ介绍1.官网2.基础概念3.组件架构 3.安装1.安装宝塔面板1.更新系统2.安装宝塔面板3.开放33142端口 2.创建存放软件的文件夹3.将软件上传到soft目录下4.安装unzip5.进入目录解压软件6.进入bin目录7.修改两个sh文件配置内存小一点8.在/usr/local/soft/ro…

Maven-08.依赖管理-生命周期

一.生命周期 Maven中的生命周期就是描述一次maven项目构建要经历那些阶段。包含clean&#xff0c;default和site三个。这三个生命周期时相互独立的。所谓相互独立&#xff0c;就是每套生命周期中的阶段互不干扰。 阶段是生命周期中最细化的操作。我们重点关注5个阶段&#xf…

教你学习企业高性能web服务器-nginx

一、web服务介绍 1、Apache的三种模型 &#xff08;1&#xff09;Apache prefork 预派生模式&#xff0c;有一个主控制进程&#xff0c;然后生成多个子进程&#xff0c;使用select模型&#xff0c;最大并发1024每个子进程有一个独立的线程响应用户请求相对比较占用内存&…

笔记(day24)正则表达式

一、正则表达式 1.1 概述 正则表达式定义了字符串的匹配模式,可以用来进行搜索,编辑,或处理文本 并不仅限于某一种语言,但是在每种语言中有细微的差别 1 数据校验、格式校验 2 数据提取 1.2 语法 元字符描述\将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如&a…

专题---自底向上的计算机网络(数据链路层)

目录 计算机网络概述 物理层 数据链路层 网络层 传输层 应用层 网络安全

pinctl 和 gpio子系统驱动

一.设备树中添加pinctl节点模板 1.创建对应的节点 同一个外设的 PIN 都放到一个节点里面&#xff0c;打开 imx6ull-14x14-evk.dts&#xff0c;在 iomuxc 节点 中的“imx6ul-evk”子节点下添加 “pinctrl_test” 节点。添加完成以后如下所示&#xff1a; pinctrl_test:test_g…