linux生产者消费者模型

今天是一个与互斥锁和条件变量有关的一个模型,生产者消费者模型,为什么要用这个模型呢?其实这个模型我个人感觉的有点就是提高了效率,在多线程的情况下,提高了非常明显。并且解耦了生产者和消费者的关系。下面是一个这个模型的基本思路:

这个模型充分说明了两者的关系,就是一个共用的资源,一个放,一个拿,且有三种关系,两种角色,一个交易场所。取数据的我们可以看成是消费者,放数据的是生产者,交易场所就是这个共用资源,而这个关系我们应该怎样理解呢?就是如果有多个生产者和消费者,那么我们就要出现一个串行关系取数据或是放数据,不然就会乱,所以会很明显的是消费者之间是互斥关系,生产者之间也是互斥,而生产者与消费者是互斥与同步的关系。,所以弄清楚了基本的模型,我们就来看看如何实现。.

注:这个交易场所也就是共用资源可以不是队列,这里只是打个比方,为了更好的理解。

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <cstring>
#include "mtx.hpp"
#include "model.hpp"
#include <time.h>
using namespace std;
//创建线程数量
#define NUMPTHREAD_T 6
//函数指针
typedef void (*func)(int);
//函数声明
void product(int number);
void custcom(int number);
proCust<int> mod;
//判断是生产者还是消费者
struct Pro_or_cust
{
    int _number;
    string _name;
    func _product = product;
    func _custcom = custcom;
    Pro_or_cust(int number)
        : _number(number)
    {
    }
};
void product(int number)
{
    while (true)
    {
        //同步所有线程
        sleep(3);
        //随机生成数,项目中一般是做其他任务
        int val = rand() % 100000;
        cout << "我是生产者" << pthread_self() << "   " << number << endl;
        mod.push(val, number);
        sleep(1);
    }
}
void custcom(int number)
{
    while (true)
    {
        cout << "我是消费者" << pthread_self() << "   " << number << endl;
        int ret = mod.pop(number);
        //打印获得数据,一般也可以处理获取的数据
        cout << "我消费的数据" << ret << endl;
        sleep(1);
    }
}
void *enter(void *args)
{
    Pro_or_cust *p = (Pro_or_cust *)args;
    //判断是生产者还是消费者
    if (strcmp(p->_name.c_str(), "custcom") == 0)
        p->_custcom(p->_number);
    else
        p->_product(p->_number);
    delete p;
    return nullptr;
}
int main()
{
    srand((unsigned int)time(nullptr));
    pthread_t tid[NUMPTHREAD_T];
    for (int i = 0; i < NUMPTHREAD_T; i++)
    {
        Pro_or_cust *str = new Pro_or_cust(i + 1);
        if (i % 2 == 0)
            str->_name = "custcom";
        else
            str->_name = "product";
        pthread_create(tid + i, nullptr, enter, str);
        // sleep(1);
    }
    for (int i = 0; i < NUMPTHREAD_T; i++)
    {
        pthread_join(tid[i], nullptr);
    }
    cout << "回收资源成功" << endl;
    return 0;
}
#pragma once
#include <iostream>
#include <unistd.h>
#include <queue>
#include <pthread.h>
#include <time.h>
#include "mtx.hpp"
#define NUMSIZE 10
using namespace std;
template <class T>
class proCust
{
public:
    proCust(size_t size = NUMSIZE)
        : _size(size)
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_full, nullptr);
        pthread_cond_init(&_empty, nullptr);
    }
    void push(const T &x, int number)
    {
        Rmtx s(_mtx);
        cout<<"我抢到锁了"<<number<<" " <<&_mtx<<endl;
        sleep(1);
        while (_size == _q.size())
        {
            pthread_cond_signal(&_empty);
            pthread_cond_wait(&_full, &_mtx);
        }
        _q.push(x);
        cout << "我是生产者:" << number << "号"
             << "  "
             << "我的tid: " << pthread_self() << endl;
        
    }
    T pop(int number)
    {
        Rmtx s(_mtx);
        cout<<"我抢到锁了"<<number<<" " <<&_mtx<<endl;
        sleep(1);
        while (_q.size() == 0)
        {
            pthread_cond_signal(&_full);
            pthread_cond_wait(&_empty, &_mtx);
        }
        T x = _q.front();
        _q.pop();
        cout << "我是消费者:" << number << "号"
             << "  "
             << "我的tid: " << pthread_self() << endl;
        return x;
    }
    ~proCust()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_full);
        pthread_cond_destroy(&_empty);
    }

private:
    size_t _size;
    queue<T> _q;
    pthread_cond_t _full;
    pthread_cond_t _empty;
    pthread_mutex_t _mtx;
};
#pragma once
#include <iostream>
#include <pthread.h>
#include <utility>
//RAII风格的加锁方式
struct Rmtx
{
public:
    Rmtx(pthread_mutex_t &mtx)
        : _mtx(mtx)
    {
        pthread_mutex_lock(&_mtx);
        std::cout << "已上锁" << std::endl;
    }
    ~Rmtx()
    {
        pthread_mutex_unlock(&_mtx);
        std::cout << "已解锁" << std::endl;
    }

private:
    pthread_mutex_t &_mtx;
};

首先是两个头文件,一个test.cc文件。

这个模型本身很简单,但是实现起来,个人认为还是要有不少注意的点,而且不好找出错误。

首先给大家说说实现这个模型我个人认为要注意的点。

1.如果有小伙伴想给新线程传编号,就是第几个创建的线程,这里一定要注意。那就是因为pthread_create这个函数本身不会有延迟,但是奈何这个函数中,是创建一个新线程,也就是说这个函数内部就会分开,一个是新线程,一个是主线程,而主线程的速度要比新线程快,所以有可能就是主线程运行到第二次循环了,新线程可能才创建好,所以这里有时候会达不到自己的预期,切代码正确,就是检查不出错误原因。

2.其次就是这个RAII的风格方式加锁,不知道大家写的时候有没有遇见过,就是把锁的初始化写到了构造函数(上面的代码是写到Rmtx中构造函数),其实这样写是错的,这样的话类似于加不上锁,我也测试了很长时间才发现,因为这样的话每个线程都会创建一个这个对象,所以会把这个锁初始化好多次,造成类似于没有加锁的那种情况,就是多线程共同访问临界资源,这个一定要注意。

我上网查了下类似于同步多次初始化的结果,但是没查到,有的也没看懂,我个人认为可能是破坏了锁,所以导致错误。

多线程部分出现错误还是比较难调试的,所以一定要小心。

希望大家支持!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索经典算法:贪心、分治、动态规划等

1.贪心算法 贪心算法是一种常见的算法范式&#xff0c;通常在解决最优化问题中使用。 贪心算法是一种在每一步选择中都采取当前状态下最优决策的算法范式。其核心思想是选择每一步的最佳解决方案&#xff0c;以期望达到最终的全局最优解。这种算法特点在于只考虑局部最优解&am…

Git设置显示中文

git config --global i18n.comitencoding utf-8 git config --global i18n.logoutputencoding utf-8 export LESSCHARSETutf-8

人声与背景音乐源分离

一.人声分离项目说明 人声分离是将音频录音分离为各个源的任务。该存储库是音乐源分离的 PyTorch 实现。用户可以通过安装此存储库将自己喜欢的歌曲分成不同的来源。用户还可以训练自己的源分离系统。该存储库还可用于训练语音增强、乐器分离和任何分离系统。 2.1 环境配置 …

[直播自学]-[汇川easy320]搞起来(3)看文档安装软件 查找设备

2023.11.09 20&#xff1a;04 按照文档 解压压缩包得到&#xff1a; 打开 里面有一条值得注意&#xff1a; 想把软件安装到C盘&#xff0c;但是C盘没什么空间了&#xff0c;把C盘清理清理。 20&#xff1a;35 安装很快完成&#xff0c;然后阅读 由于PLC是新的&#xff0c…

django安装和rest接口写法

django安装 确保已经安装了Python。命令行中输入python --version来检查Python的版本。 安装Django。你可以在命令行中使用以下命令来安装Django&#xff1a; pip install django创建一个新的Django项目。在命令行中&#xff0c;进入你想要创建项目的目录&#xff0c;并运行以…

vscode 访问本地或者远程docker环境

1、vscode 访问docker本地环境 直接点击左下角连接图标&#xff0c;弹出选项可以选择容器&#xff0c;只要容器在本地运行者&#xff0c;选择attach可以看到运行中的容器可以选择&#xff0c;选择其中需要选择的就行 ## 运行容器&#xff0c;可以-d后台运行都可以 docker run…

跨时钟域(Clock Domain Crossing,CDC)

本文参考&#xff1a;http://t.csdnimg.cn/VHga2 【数字IC基础】跨时钟域&#xff08;CDC&#xff0c;Clock Domain Crossing&#xff09;_ReRrain的博客-CSDN博客 同步设计&#xff1a;所有设计使用同一时钟源&#xff0c;频率相位可预知。 异步设计&#xff1a;设计中有两…

RPC接口测试技术-websocket 自动化测试实践

WebSocket 是一种在单个 TCP 连接上进行全双工通信(Full Duplex 是通讯传输的一个术语。通信允许数据在两个方向上同时传输&#xff0c;它在能力上相当于两个单工通信方式的结合。全双工指可以同时&#xff08;瞬时&#xff09;进行信号的双向传输&#xff08; A→B 且 B→A &a…

elementui-plus el-tree组件数据不显示问题解决

当前情况: 显示: 注意看右侧的树是没有文字的,数据已经渲染,个数是对的,但就是没有文字, 解决: 对比以后发现是template中的#default{data}没有写大括号导致的 所以写上大括号后: 正常显示

ArcGIS 气象风场等示例 数据制作、服务发布及前端加载

1. 原始数据为多维数据 以nc数据为例。 首先在pro中需要以多维数据的方式去添加多维数据&#xff0c;这里的数据包含uv方向&#xff1a; 加载进pro的效果&#xff1a; 这里注意 数据属性需要为矢量uv&#xff1a; 如果要发布为服务&#xff0c;需要导出存储为tif格式&…

C语言编写一个程序采集招聘信息

因为在这里无法详细解释每行代码和步骤。但是&#xff0c;我可以给大家一个使用Python和requests库编写的简单爬虫程序的例子&#xff0c;它可以从网站上获取招聘信息。你可以根据这个例子&#xff0c;将其改写为使用C语言编写的爬虫程序。 import requests# 指定爬虫IP信息 pr…

javaScript爬虫程序抓取评论

由于评论区目前没有开放的API接口&#xff0c;所以我们不能直接通过编程获取到评论区的内容。但是&#xff0c;我们可以通过模拟浏览器的行为来实现这个功能。以下是一个使用Python的requests库和BeautifulSoup库来实现这个功能的基本思路&#xff1a; import requests from bs…

Matlab论文插图绘制模板第125期—特征渲染的三维气泡图

在之前的文章中&#xff0c;分享了很多Matlab三维气泡图的绘制模板&#xff1a; 进一步&#xff0c;再来分享一下特征渲染的三维气泡图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自行下载。有需要的…

Qt 自定义控件-支持换行和点击事件的Label

目录 前言1、功能描述2、代码实现2.1 头文件2.2 源码文件2.3 设计思路 3、示例4、总结 前言 本文主要介绍一个自定义控件&#xff0c;支持换行和点击事件的Label。起因是有这样一个需求&#xff0c;在一个复杂系统中有一个页面可以显示该系统中所有设备的名字&#xff0c;并且…

【Redis】Redis整合SSMRedis注解式缓存Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(详解)

目录&#xff1a; 目录 一&#xff0c;SSM整合redis 二&#xff0c;redis注解式缓存 三&#xff0c;Redis中的缓存穿透、雪崩、击穿的原因以及解决方案&#xff08;附图&#xff09; 一&#xff0c;SSM整合redis 1.原因&#xff1a; 整合SSM和Redis可以提升系统的性能、可…

骑士巡游问题

一、骑士巡游问题 题目描述&#xff1a;骑士在8*8的国际象棋棋盘上进行巡游&#xff0c;当指定骑士出发的位置后&#xff08;x,y&#xff09;&#xff0c;能输出骑士遍历棋盘的所有路径坐标。 输出效果&#xff1a; 代码&#xff08;请在visual stdio下运行&#xff0c;Dev-C…

腾讯蒋杰:坚持用技术服务应用,腾讯混元大模型已接入180多个业务

“腾讯正在持续探索大模型应用场景&#xff0c;目前内部超180项业务已经接入腾讯混元大模型进行内测”&#xff0c;11月9日&#xff0c;腾讯集团副总裁蒋杰在2023年世界互联网大会乌镇峰会上表示。 腾讯集团副总裁 蒋杰 作为腾讯全链路自研的实用级大模型&#xff0c;自2023年…

MySQL(12):MySQL数据类型

MySQL中的数据类型 常见数据类型的属性&#xff1a; 整数类型 整数类型一共有 5 种&#xff0c;包括 TINYINT、SMALLINT、MEDIUMINT、INT&#xff08;INTEGER&#xff09;和 BIGINT。 CREATE TABLE test_int1 ( X TINYINT, y SMALLINT, z MEDIUMINT, m INT, n BIGINT );…

在linux上脱离hadoop安装hbase-2.5.6集群

一、软件版本 1.1、jdk1.8 1.2、hbase 2.5.6 1.3、zookeeper 3.8.1 二、计算节点 准备三台服务器 192.168.42.139 node1 192.168.42.140 node2 192.168.42.141 node3三、配置环境 1、每台服务器都配置jdk环境变量 [rootnode1 data]# javac -version javac 1.8.0_3912、每…

《童年》 思维导图

《童年》是高尔基自传体小说三部曲中的第一部&#xff0c;讲述的是高尔基幼年丧父、母亲改嫁&#xff0c;他跟随日渐破落的小染坊主外公以及外婆生活的童年经历。小说通过一个儿童天真无邪的眼光&#xff0c;向读者生动地展示了19世纪中叶俄罗斯社会底层人民的生活状态&#xf…