LINUX系统编程:基于环形队列和信号量的生产者消费者模型

news2024/9/22 21:29:11

目录

1.环形队列

2.加上信号量的理解

3.代码


1.环形队列

环形队列使用vector封装出来的。

环形队列可以实现并发生产和消费,就是在消费的同时也可以生产。

这个是建立在生产者消费者位置不重合的情况下。

因为位置重合之后,环形队列为空或者满,

为空的时,只能让生产者先生产,消费者后消费,

为满时,消费者先消费,生产者后生产。

如何实现环形的效果

当下标遍历到vector末尾的时候, 下标 %=判断环形队列为空还是为满 vector容量,下标就回到数组的开始。

当生产者消费者重合时

1.队列为空(访问环形队列,让生产者先生产)

2.队列为满(访问环形队列,让消费者先消费)

当生产者与消费者不重合时

队列一定不为空&&不为满,这个时候生产者可以生产,消费者可以消费。

2.加上信号量的理解

生产者只关心环形队列有没有空间让他生产

消费者只关心环形队列有没有数据让他消费

信号量是一种资源预定机制,预定成功之后肯定会有空间和数据,给消费者和生产者

所以生产者在生产之前要对空间的信号量进行p操作,生产完成之后要对数据的信号量进行v操作

所以消费者在生产之前要对数据的信号量进行p操作,消费完成之后要对空间的信号量进行v操作

3.代码

ringqueue.hpp

#ifndef __RINGQUEUEHPP__
#define __RINGQUEUEHPP__
#include<pthread.h>
#include<thread>
#include<vector>
#include<semaphore.h>
#include"Task.hpp"
#include <iostream>
#include <string.h>
template<class T>
class ringqueue
{
private:
    void p(sem_t &sem)
    {
        int ret = sem_wait(&sem);
        if(ret == -1)
        {
            std::cout<< strerror(errno) <<std::endl;
        }
    }

    void v(sem_t &sem)
    {
       int ret = sem_post(&sem);
        if(ret == -1)
        {
            std::cout<< strerror(errno) <<std::endl;
        }
    }

public:
    ringqueue(int cap = 8)
    :_ringqueue(cap)
    ,_cap(cap)
    ,p_step(0)
    ,c_step(0)
    {
        sem_init(&_room,0,cap);
        sem_init(&_data,0,0);
        pthread_mutex_init(&c_mutex,nullptr);
        pthread_mutex_init(&p_mutex,nullptr);
    }

    //生产者向队列里生产
    void enqueue(T in)
    {   
        p(_room); // 申请空间
        pthread_mutex_lock(&p_mutex);
        _ringqueue[p_step++] = in;
        p_step %= _cap;
        pthread_mutex_unlock(&p_mutex);
        v(_data); // 生产之后资源++
        
        
    }   

    void pop(T &out)
    {
        //int roomnum = 0;
        //int datanum = 0;
        //sem_getvalue(&_room,&roomnum);
        //sem_getvalue(&_data,&datanum);
        //std::cout<< roomnum <<" " <<datanum <<std::endl;
        p(_data); //申请资源
        pthread_mutex_lock(&c_mutex);
        
        out = _ringqueue[c_step++];
        c_step %= _cap;
        pthread_mutex_unlock(&c_mutex);
        v(_room);
        
    }

    ~ringqueue()
    {
        sem_destroy(&_room);
        sem_destroy(&_data);
        pthread_mutex_destroy(&p_mutex);
        pthread_mutex_destroy(&c_mutex);
    }

private:
    std::vector<T> _ringqueue;
    int _cap;//容量

    int p_step ;//生产者下次生产的位置
    int c_step ;//消费者下次消费的位置

    sem_t _room; //空间
    sem_t _data; //资源

    pthread_mutex_t p_mutex; //为了多生产之间的互斥关系
    pthread_mutex_t c_mutex; //为了多消费之间的互斥关系
};





#endif

Task.hpp

#ifndef __TASKHPP__
#define __TASKHPP__

#include<string>
#include<iostream>
class Task
{
public:
    Task():taskname("未知任务"){}

    Task(std::string name)
    :taskname(name)
    {}

    void excute()
    {
        std::cout<<"Excute " << taskname <<std::endl;
    }

    std::string & name()
    {
        return taskname;
    }
private:
    std::string taskname;
};






#endif

Main.cc

#include "Task.hpp"
#include "ringqueue.hpp"
#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <time.h>
#include <unistd.h>
std::vector<std::string> Taskarr{"Download", "UPLoad", "cacluate"};

void product(void* args)
{
    ringqueue<Task>* rq = (ringqueue<Task>*)args;
    srand(time(nullptr));
    while (true)
    {
        sleep(1);
        Task task(Taskarr[rand() % 3]);
        rq->enqueue(task);
        std::cout << "product task "<< task.name() << std::endl;
    }
}

//void consum(ringqueue<Task> &rq)
//用指針的方式传递参数,把ringqueue的指针传过来,
void consum(void* args)
{
    ringqueue<Task>* rq = (ringqueue<Task>*)args;
    sleep(6);
    while (true)
    {
        sleep(1);
        Task task;
        rq->pop(task);
        task.excute(); 
        
    }
}
//是不是这里的问题 这里传过去的时候发生了拷贝
//是的
void product_start(std::vector<std::thread> &threadss, ringqueue<Task> &rq, int num)
{
    for (int i = 0; i < num; i++)
    {
        threadss.emplace_back(product, (void*)&rq);
    }
}

void consumer_start(std::vector<std::thread> &threadss, ringqueue<Task> &rq, int num)
{
    for (int i = 0; i < num; i++)
    {
        threadss.emplace_back(consum, (void*)&rq);
    }
}

void Waitall(std::vector<std::thread> &threadss)
{
    for (auto &thread : threadss)
    {
        thread.join();
    }
}

int main()
{
    std::vector<std::thread> threadss;

    ringqueue<Task> rq(5);
    product_start(threadss, rq,3);
    consumer_start(threadss, rq, 5);

    Waitall(threadss);

    return 0;
}

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

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

相关文章

Tomcat组件概念和请求流程

Tomcat:是一个Servlet容器(实现了Container接口)&#xff0c;容器分层架构从上到下分为。Engine(List<Host>)->Host(List<Context>)->Context(List<Wrapper>)->Wrapper(List<Servlet>); Engine:引擎&#xff0c;Servlet 的顶层容器&#xff0…

使用uni-app和Golang开发影音类小程序

在数字化时代&#xff0c;影音内容已成为人们日常生活中不可或缺的一部分。个人开发者如何快速构建一个功能丰富、性能优越的影音类小程序&#xff1f;本文将介绍如何使用uni-app前端框架和Golang后端语言来实现这一目标。 项目概述 本项目旨在开发一个个人影音类小程序&#…

dm-verity hashtree的结构

参考了&#xff1a;实现 dm-verity | Android Open Source Project (google.cn)。基于这个添加了一层原始数据&#xff0c;便于理解。 结构图如下&#xff1a; 对hashtree结构图的解释&#xff1a; dev data&#xff1a;表示我们的分区数据。这里我们将dev data按照指定的大…

计网(1.1~1.4)

1.1计算机网络在信息时代的作用 21世纪的重要特征数字化、网络化和信息化 有三类网络&#xff1a;电信网络、有线电视网络和计算机网络 互联网两个重要基本特点&#xff0c;即连通性和共享 1.2因特网概述 &#xff08;1&#xff09;网络、互联网和互连网 网络:由若干结点和连接…

安装jenkins最新版本初始化配置及使用JDK1.8构建项目详细讲解

导读 1.安装1.1.相关网址1.2.准备环境1.3.下载安装 2. 配置jenkins2.1.安装插件2.2.配置全局工具2.3.系统配置 3. 使用3.1.配置job3.2.构建 提示&#xff1a;如果只想看如何使用jdk1.8构建项目&#xff0c;直接看3.1即可。 1.安装 1.1.相关网址 Jenkins官网&#xff1a;https…

LabVIEW前面板占满整个屏幕(转)

希望在运行一个LabVIEW程序时&#xff0c;它的前面板能够占据整个屏幕&#xff0c;且不显示Windows的任务栏或其他任何的LabVIEW菜单选项。怎样才能实现这一功能&#xff1f; 您可以通过手动配置或编程的方式实现该功能。 手动配置VI属性 您可以通过以下操作&#xff0c;将…

Java毕业设计 基于SSM vue电影订票系统小程序 微信小程序

Java毕业设计 基于SSM vue电影订票系统小程序 微信小程序 SSM 电影订票系统小程序 功能介绍 用户 登录 注册 忘记密码 首页 图片轮播 电影信息 电影详情 评论 收藏 预订 电影资讯 资讯详情 用户信息修改 电影评价 我的收藏管理 用户充值 在线客服 我的订单 管理员 登录 个人…

paloalto防火墙CLI修改MGT IP

怎么样通过Cli修改MGT口的IP、掩码、网关、DNS呢&#xff1f; 1&#xff09;console连接上CLi&#xff0c;输入configure进入系统视图 输入exit&#xff0c;退出到用户视图 2&#xff09;在CLI修改带外管理MGT的IP地址、掩码、网关、DNS&#xff0c;默认带外管理是开启https、…

使用offset explorer 3.0连接单机版kafka

一、目标 使用kafka图形化工具offset explorer 3.0连接单机版的kafka 二、windows下载安装offset explorer 3.0 1、kafka tool工具官方下载页面 Offset Explorer https://www.kafkatool.com/download.html 2、安装offset explorer 3.0 下一步&#xff0c;下一步&#xff0…

html设计(两种常见的充电效果)

第一种 完整代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&…

Kotlin Misk Web框架

Kotlin Misk Web框架 1 Misk 框架介绍2 Misk/SpringBoot 框架对比3 Misk 添加依赖/配置3.1 build.gradle.kts3.2 settings.gradle.kts3.3 gradle.properties 4 Misk 请求接口5 Misk 程序模块6 Misk 主服务类7 Misk 测试结果 1 Misk 框架介绍 Misk 是由 Square 公司开发的一个开…

FSD渐入佳境,视觉方案还在机器人中“打酱油”?

一边是技术圈顶流&#xff0c;一边在当前行业应用中没什么存在感。 优点缺点&#xff0c;两头拔尖 优点与缺点都突出的特点&#xff0c;让视觉方案一直伴随着争议&#xff0c;在近些年的行业应用上也一直透着“底气”不足。但随着在自动驾驶方面&#xff0c;纯视觉FSD开始表现…

【Linux】|开发工具介绍 | yum |vim | gcc/g++ | gdb | git

Linux开发工具详解 1. 引言&#x1f4a6;2. Linux软件包管理器&#xff1a;Yum什么是软件包安装和卸载软件rzsz工具 3. Linux编辑器&#xff1a;VimVim的基本概念Vim的基本操作Vim模式和命令集&#x1f433;Vim配置 4. Linux编译器&#xff1a;GCC/G编译过程详解编译器的自举函…

如何通过兔子和窝窝的故事理解“在机器人学习和研究中的获得成本与维护成本”(节选)

获得成本 掌握一门课程&#xff0c;以最为简单的学校成绩过60为例&#xff0c;需要按要求提交材料&#xff0c;包括作业、报告、实验和考试等&#xff0c;依据学分和考核要求的不同&#xff0c;需要对于花费时间和经历进行完成。 维护成本 考完了&#xff0c;如果被动学习那…

Django 删除单行数据

1&#xff0c;添加模型 from django.db import modelsclass Post(models.Model):title models.CharField(max_length200)content models.TextField()pub_date models.DateTimeField(date published)class Book(models.Model):title models.CharField(max_length100)author…

安防监控视频平台LntonCVS视频融合共享平台智慧消防实现远程集中视频监控方案

近年来&#xff0c;电力系统内变电站着火事件频发&#xff0c;这对消防安全管理提出了严峻挑战。我国消防安全基础设施不完善、管理机制不健全、应急处置能力不足及公众消防安全意识淡薄等问题&#xff0c;严重制约了消防安全的提升。因此&#xff0c;加强变电站的消防安全管理…

Python应用爬虫下载QQ音乐歌曲!

目录&#xff1a; 1.简介怎样实现下载QQ音乐的过程&#xff1b; 2.代码 1.下载QQ音乐的过程 首先我们先来到QQ音乐的官网&#xff1a; https://y.qq.com/&#xff0c;在搜索栏上输入一首歌曲的名称&#xff1b; 如我在上输入最美的期待&#xff0c;按回车来到这个画面 我们首…

nx上darknet的使用-目标检测-在python中的使用

1 内置的代码 在darknet中已经内置了两个py文件 darknet_video.py与darknet_images.py用法类似&#xff0c;都是改一改给的参数就行了&#xff0c;我们说一下几个关键的参数 input 要预测哪张图像weights 要使用哪个权重config_file 要使用哪个cfg文件data_file 要使用哪个da…

240712_昇思学习打卡-Day24-LSTM+CRF序列标注(3)

240712_昇思学习打卡-Day24-LSTMCRF序列标注&#xff08;3&#xff09; 今天做LSTMCRF序列标注第三部分&#xff0c;同样&#xff0c;仅作简单记录及注释&#xff0c;最近确实太忙了。 Viterbi算法 在完成前向训练部分后&#xff0c;需要实现解码部分。这里我们选择适合求解…

Android Gantt View 安卓实现项目甘特图

需要做一个项目管理工具&#xff0c;其中使用到了甘特图。发现全网甘特图解决方案比较少&#xff0c;于是自动动手丰衣足食。 前面我用 Python和 Node.js 前端都做过&#xff0c;这次仅仅是移植到 Android上面。 其实甘特图非常简单&#xff0c;开发也不难&#xff0c;如果我…