【Linux 多线程同步】使用同步和互斥实现生产消费模型

news2024/12/23 23:40:58

目录

1.同步的接口

2.多线程但是按顺序来执行

3.生产消费模型

4.使用互斥加同步实现生产消费模型 (采用环形队列)


同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题

1.同步的接口

pthread_cond_t 是条件变量;

 

2.多线程但是按顺序来执行

  • 保证了每个线程都被执行,没有饥饿问题
#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;

pthread_cond_t cond;//条件变量
pthread_mutex_t mtx;
void* Work(void* args)
{
    int num=*((int*)args);
    delete (int*)args;
    while(1)
    {
        pthread_cond_wait(&cond,&mtx);
        cout<<"worker: "<<num<<endl;
    }
}
void* Control(void* args)
{
    while(1)
    {
        pthread_cond_signal(&cond);
        sleep(1);
    }
}
int main()
{
    //初始化条件变量和互斥锁
    pthread_cond_init(&cond,NULL);
    pthread_mutex_init(&mtx,NULL);
    pthread_t master;
    pthread_t worker[5];

    for(int i=0;i<5;i++){//5个轻量级进程
        int* tmp=new int(i);
        pthread_create(worker+i,NULL,Work,(void*)tmp);
    }
    pthread_create(&master,NULL,Control,NULL);//使用同步管理另外5个轻量级进程按特定顺序执行

    //等待轻量级进程
    for(int i=0;i<5;i++)
    {
        pthread_join(worker[i],NULL);
    }
    //释放条件变量和互斥锁
    pthread_join(master,NULL);
    pthread_cond_destroy(&cond);
    return 0;
}

 执行结果:

3.生产消费模型

4.使用互斥加同步实现生产消费模型 (采用环形队列)

条件变量判断应采用while而不是if,线程被挂起其他,线程可能会修改临界资源,pthread_cond_signal唤醒线程可能条件不再满足;

if(判断条件)//不完全正确的
    {
        pthread_cond_wait(&_cond,&_mtx);
    }
while(判断条件)//正确
    {
        pthread_cond_wait(&_cond,&_mtx);
    }

BlockQueue.hpp

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

#define CAPACITY 10

namespace ds_blockqueue{
    template<class T>
    class BlockQueue
    {
    private:
        std::queue<T> bq;//先入先出队列
        int cap;//容量
        //两个条件变量和一个互斥锁
        pthread_cond_t pc;
        pthread_cond_t cc;
        pthread_mutex_t mtx;
    public:
        BlockQueue()
            :cap(CAPACITY)
        {
            pthread_cond_init(&pc,nullptr);
            pthread_cond_init(&cc,nullptr);
            pthread_mutex_init(&mtx,nullptr);
        }
        ~BlockQueue()
        {
            pthread_cond_destroy(&pc);
            pthread_cond_destroy(&cc);
            pthread_mutex_destroy(&mtx);
        }
    private:
        void WaitProducer()
        {
            pthread_cond_wait(&pc,&mtx);
        }
        void WaitConsumer()
        {
            pthread_cond_wait(&cc,&mtx);
        }
        void WakeupProducer()
        {
            pthread_cond_signal(&pc);
        }
        void WakeupConsumer()
        {
            pthread_cond_signal(&cc);
        }
        void Lock()
        {
            pthread_mutex_lock(&mtx);
        }
        void Unlock()
        {
            pthread_mutex_unlock(&mtx);
        }
    private:
        bool IsFull()
        {
            return bq.size()==cap;
        }
        bool IsEmpty()
        {
            return bq.size()==0;
        }
    public:
        //当满时生产者需要等待消费者消费
        //当空时消费者需要等待生产者生产
        void Push(const T& in)
        {
            Lock();
            while(IsFull())//被挂起如果其他轻量级进程修改临界资源,使用if判断这个条件条件不一定是满足的使用while免得伪唤醒
            {
                WaitProducer();
            }
            bq.push(in);
            //生成一个就可以消费了
            //if(bq.size()>=cap/2)
                WakeupConsumer(); 
            Unlock();
        }
        void Pop(T* out)
        {
            Lock();
            while(IsEmpty())//被挂起如果其他轻量级进程修改临界资源,使用if判断这个条件条件不一定是满足的使用while免得伪唤醒
            {
                WaitConsumer();
            }
            *out=bq.front();
            bq.pop();
            //消费一个就可以生产了
            //if(bq.size()<=cap/2)
                WakeupProducer();
            Unlock();
        }
    };
}

cp_test.cc

#include "BlockQueue.hpp"
#include "Task.hpp"
#include<unistd.h>
#include<cstdlib>
#include<time.h>
using namespace ds_blockqueue;
using namespace ds_task;

const char* op="+-*/";
void* Consumer(void* args)
{
    BlockQueue<Task>* bq=(BlockQueue<Task>*)args;
    while(true)
    {
        Task t;
        int data=0;
        bq->Pop(&t);
        std::cout<<"消费数据:";
        t();
        sleep(1);
    }
}
void* Producer(void* args)
{
    BlockQueue<Task>* bq=(BlockQueue<Task>*)args;
    while(true)
    {

        int x=rand()%20+1;
        int y=rand()%20+1;
        char tmp=op[rand()%4];
        Task t(x,y,tmp);
        
        // //制造数据
        // int data=rand()%10+1;
        //std::cout<<"生产数据:"<<data<<std::endl;
        std::cout<<"生产数据:"<<x<<tmp<<y<<std::endl;
        bq->Push(t);
        sleep(2);
    }
}
int main()
{
    srand((long long)time(nullptr));
    BlockQueue<Task>* bq=new BlockQueue<Task>;//创建阻塞队列
    pthread_t pid1;
    pthread_t pid2;
    //创建消费者和生产者
    pthread_create(&pid1,nullptr,Consumer,(void*)bq);
    pthread_create(&pid2,nullptr,Producer,(void*)bq);

    pthread_join(pid1,nullptr);
    pthread_join(pid2,nullptr);
    return 0;
}

Task.hpp:处理数据

#include<iostream>

namespace ds_task{
    class Task

    {
    private:
        int _x;
        int _y;
        char _op;
    public:
        Task()
        {}
        Task(const int& x,const int& y,const char&  op)   
            :_x(x)
            ,_y(y)
            ,_op(op) 
        {}
        ~Task()
        {}
        void operator()()
        {
            int tatol=0;
            switch(_op)
            {
                case '+':
                    tatol=_x+_y;
                    break;
                case '-':
                    tatol=_x-_y;
                    break;
                case '*':
                    tatol=_x*_y;
                    break;
                case '/':
                    tatol=_x/_y;
                    break;
                default:
                    break;
            }
            std::cout<<_x<<_op<<_y<<"="<<tatol<<std::endl;
        }
    };
}

执行结果:

 

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

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

相关文章

GraphTrip论文笔记【Information Fusion 92 (2023)】

Dual-grained human mobility learning for location-aware trip recommendation with spatial–temporal graph knowledge fusion 期刊&#xff1a;EI检索 Information Fusion 92 (2023) Challenges &#xff08;1&#xff09;异质交互信息的挖掘 POI位置信息、POI类别信息…

重新标记ImageNet:从全局标签到局部标签(附github代码及论文)

欢迎关注“计算机视觉研究院”计算机视觉研究院专栏作者&#xff1a;Edison_GImageNet可以说是最受欢迎的图像分类基准&#xff0c;但它也是一个具有显著噪声的标签。最近的研究表明&#xff0c;许多样本包含多个类&#xff0c;尽管被假定为单个标签基准。因此&#xff0c;他们…

【办公类-18-02】Python VScode 制作“照片整理.py”的exe文件(打包系列)

效果展示&#xff1a;背景需求&#xff1a;最近一年我都是机动班&#xff08;非固定班主任&#xff09;&#xff0c;所以拍的照片不多&#xff0c;只需要每月把手机里的照片用QQ的“我的文件助手”导出来&#xff0c;然后打开VScode&#xff0c;找到“20211020按日期批量整理文…

独居老人一键式报警器

盾王居家养老一键式报警系统&#xff0c;居家养老一键式报警设备 &#xff0c;一键通紧急呼救设备&#xff0c;一键通紧急呼救系统&#xff0c;一键通紧急呼救器 &#xff0c;一键通紧急呼救终端&#xff0c;一键通紧急呼救主机终端产品简介&#xff1a; 老人呼叫系统主要应用于…

java网络编程-nio学习:阻塞和非阻塞

一、阻塞 阻塞模式下&#xff0c;相关方法都会导致线程暂停 ServerSocketChannel.accept 会在没有连接建立时让线程暂停 SocketChannel.read 会在没有数据可读时让线程暂停 阻塞的表现其实就是线程暂停了&#xff0c;暂停期间不会占用 cpu&#xff0c;但线程相当于闲置 单线…

Learning C++ No.11【string类实现】

引言&#xff1a; 北京时间&#xff1a;2023/2/19/8:48&#xff0c;昨天更新了有关进程状态的博客&#xff0c;然后在休息的时候&#xff0c;打开了腾讯视屏&#xff0c;然后看到了了一个电视剧&#xff0c;导致上头&#xff0c;从晚上6点看到了10点&#xff0c;把我宝贵的博客…

vue(5)

文章目录1. 监测数据原理1.1 通过问题引出1.2 开始1.3 Vue.set() 方法1.4 vue 监视 数组1.5 小练习2. 收集表数据3. 过滤器4. 内置指令4.1 v-text4.2 v-html4.3 v-cloak4.4 v-once4.5 v-pre1. 监测数据原理 1.1 通过问题引出 1.2 开始 要想解决上面的这个问题 &#xff0c;需要…

python基于django幼儿园管理系统

目录 1 绪论 1 1.1课题背景 1 1.2课题研究现状 1 1.3初步设计方法与实施方案 2 1.4本文研究内容 2 2 系统开发环境 4 2.1 JAVA简介 4 2.2MyEclipse环境配置 4 2.3 B/S结构简介 4 2.4MySQL数据库 5 2.5 SPRINGBOOT框架 5 3 系统分析 6 3.1系统可行性分析 6 3.1.1经济可行性 6 3…

【2022.12.9】Lammps+Python 在计算g6(r)时遇到的问题

目录写在前面绘制g6( r )执行步骤【updated】如何检查图像的正确性&#xff1a;不是编程问题&#xff0c;而是数学问题的一个小bug废稿2则&#xff1a;写在前面 全部log&#xff1a; 【2022.11.16】LammpsPythonMATLAB在绘制维诺图时遇到的问题 绘制g6( r )执行步骤【updated…

Eureka原理浅析

文章目录1.简介2.组件2.1 Eureka Server2.1.1 主要功能2.1.2 自我保护机制2.1.3 数据同步方式2.1.4 Server的多级缓存和Client实例过期策略2.2 Eureka Client3.补充3.1 CAP偏重点3.2 功能扩展性3.3 工作流程1.简介 Eureka是Netflix开发的服务发现框架&#xff0c;本身是基于RE…

SegNeXt: 重新思考基于卷积注意力的语义分割

论文信息 论文名称&#xff1a;SegNeXt: Rethinking Convolutional Attention Design for Semantic Segmentation 项目GitHub&#xff1a; GitHub - Visual-Attention-Network/SegNeXt: Official Pytorch implementations for "SegNeXt: Rethinking Convolutional Atten…

ESP-C3入门11. 创建最基本的HTTP请求

ESP-C3入门11. 创建最基本的HTTP请求一、menuconfig配置二、配置 CMakeLists1. 设置项目的额外组件目录2. 设置头文件搜索目录三、在 ESP32 上执行 HTTP 请求的基本步骤1. 创建 TCP 连接2. 设置 HTTP 请求3. 发送 HTTP 请求4. 接收 HTTP 响应5. 处理 HTTP 响应6. 关闭 TCP 连接…

35岁以上的大龄测试员们,后来都干什么去了?

为什么软件测试行业看不见白发苍苍的软件测试员?大龄测试员都去哪里了?各个公司会辞退大龄测试员吗? 如果一位 50 多岁的测试员申请 20 多岁或 30 多岁的职位&#xff0c;有多少公司会雇用他们呢?关于这个问题&#xff0c;有很多流言传说&#xff0c;也有一些残酷的现实。…

努力优化和改造不好的环境,去设计新的、积极的、适合自己的环境

你知道环境对你的影响有多大吗&#xff1f;自己的的社交圈也是一个环境如果你待在一个只知道吃喝玩乐&#xff0c;不思进取&#xff0c;天天玩手机、打游戏的圈子里那你很大程度也会被影响&#xff0c;因为你不跟他们一起你就融入不进去&#xff0c;就会被孤立&#xff0c;很多…

优秀蓝牙耳机推荐,热销不错的四款蓝牙耳机推荐

蓝牙耳机作为目前最流行的数码产品&#xff0c;受到很多人追捧&#xff0c;蓝牙耳机摆脱了有线蓝牙耳机的束缚&#xff0c;能够更好听歌打游戏&#xff0c;随时取用&#xff0c;更为便利&#xff0c;当然&#xff0c;随着耳机的大幅度创新&#xff0c;也导致很多人在选购耳机的…

内网渗透(四十三)之横向移动篇-SMB远程执行命令横向移动

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

前端性能优化的一些技巧(90% chatGpt生成)

终于弄好了chatGpt的账号&#xff0c;赶紧来体验一波。先来一波结论&#xff0c;这篇文章的主要内容来源&#xff0c;90%是用chatGpt生成的。先上chatGpt的生成的结果&#xff1a;作为一名懒惰的程序员&#xff0c;chatGpt会帮助我变得更懒...&#xff0c;好了下面开始文章的正…

GEE学习笔记 六十八:【GEE之Python版教程二】配置Python开发环境

这一篇内容主要讲解两部分内容&#xff0c;第一部分是本地python开发环境的配置&#xff0c;第二部分是GEE的python开发环境配置。我这里做的所有的操作都是在我的Mac电脑上做的&#xff0c;Windows上操作类似&#xff0c;如果有不清楚的可以自行搜索相关操作步骤。 第一部分&…

pytorch零基础实现语义分割项目(四)——模型训练与预测

模型训练与预测项目列表前言损失函数one_hotDice LossFocal Loss模型参数与训练预测项目列表 语义分割项目&#xff08;一&#xff09;——数据概况及预处理 语义分割项目&#xff08;二&#xff09;——标签转换与数据加载 语义分割项目&#xff08;三&#xff09;——语义…

winserver服务器硬盘满了怎么清理? 服务器硬盘空间不足清理方法

本文主要介绍我在维护windows server服务器期间总结的一些磁盘清理方式。如对您有所帮助&#xff0c;不甚荣幸。 文章目录一、C盘清理1. System32的日志文件2. IIS的日志文件3. .Net Framework的缓存文件4. 清理其他不必要文件5. 虚拟内存从c盘移到其他硬盘二、其他软件清理1. …