Linux下POSIX信号量以及基于环形队列的生产消费模型

news2024/10/6 6:46:14

目录

一、POSIX信号量介绍

1. 信号量原理

2,初始化信号量

3,信号量销毁

 4,信号量等待

5,发布信号量

 二,基于环形队列的生产消费模型

1.基于单线程

2,测试:

 3,基于多线程

4,测试 

三,代码链接


一、POSIX信号量介绍

1. 信号量原理

用于同步操作,以达到无冲突访问资源的目的,本质上起始就是一个计数器,用来描述临界资源中资源数目的计数器,处理有实现同步与互斥的功能之外,还可以更细粒度的管理临界资源。

资源划分:

           可以的。临界区的资源也是可以按照小快区域进行划分的,这个由程序员自己控制,比如一个队列啊、或者一个数组啊等等,也可以自己实现划分。

       信号量的本质是一个计数器,我们回忆一下锁:只要我申请到了锁,那么我哪怕不使用,那块资源也是我的。这就好比信号量,只要你申请到了信号量,那么你就一定属于你的资源,至于那一快资源,不知道,但是一定是有的,二元信号量==互斥锁。

2,初始化信号量

pshared:0表示线程间共享,非0表示进程间共享。
value:初始化信号量。

3,信号量销毁

 销毁指定信号量。

 4,信号量等待

相当于--信号量,也相当于申请信号量资源。

三个函数分别有不同的功能.一般第一个就够了。用到再去查文档。

5,发布信号量

相等于++信号量,也相当于归还资源。

 二,基于环形队列的生产消费模型

和基于阻塞队列的生产消费模型差不多的,这里这里该用信号量和互斥锁来控制同步互斥关系。

1.基于单线程

ring_queue.hpp:基于

#pragma once
#include <iostream>
#include <pthread.h>
#include<unistd.h>
#include <vector>
#include <string>
#include <semaphore.h>

const int cap_ = 10;
using namespace std;
template <class T>
class ring_queue
{

public:

    ring_queue(int cap = cap_)
        :ringq_(cap),
         spaceindex(0), 
         dataindex(0)
    {
        // 初始化信号量
        sem_init(&space_sem_, 0, ringq_.size());
        sem_init(&data_sem_, 0, 0);
        // 初始化互斥锁
        pthread_mutex_init(&space_mutex, nullptr);
        pthread_mutex_init(&data_mutex, nullptr);
    }

    // 生产数据
    void push(const T &in)
    {
        // 申请信号量
        sem_wait(&space_sem_);

        ringq_[spaceindex] = in;
        spaceindex++;
        spaceindex %= ringq_.size();

        // 空间资源用掉一个,数据资源就增加一个。
        sem_post(&data_sem_);
    }

    // 消费数据
    T pop()
    {

        // 申请数据资源,信号量
        sem_wait(&data_sem_);

        T tmp = ringq_[dataindex];
        dataindex++;
        dataindex %= ringq_.size();

        // 消耗一个数据资源,空间资源就会多一个
        sem_post(&space_sem_);

        return tmp;
    }

private:
    vector<T> ringq_; // 数组模拟环形队列。
    sem_t space_sem_; // 记录空间资源个数
    sem_t data_sem_;  // 记录数据资源个数
    int spaceindex;   // 空间资源起始下标
    int dataindex;    // 数据资源起始下标

    pthread_mutex_t space_mutex; // 多线程保护spaceindex++;
    pthread_mutex_t data_mutex;  // 多线程保护dataindex++;
};

 ring_test.cpp

#include <ctime>
#include "ring_queue.hpp"
#include <vector>
using namespace std;

void *consumer(void *args)
{
    ring_queue<int> *ringq = (ring_queue<int> *)args;

    while (true)
    {
        int tmp = ringq->pop();
        cout << "我是消费者,我的id:" << pthread_self() << "消费数据:" << tmp << endl;
        sleep(1);
    }
}
void *productor(void *args)
{
    ring_queue<int> *ringq = (ring_queue<int> *)args;
    while (true)
    {
        int data = rand() % 50;
        ringq->push(data);
        cout << "我是生产者,我的id:" << pthread_self() << "生产数据:" <<data << endl;

        // sleep(1);
    }
}
int main()
{

    srand(time(0));
    ring_queue<int> ringq(10);

    pthread_t t1;
    pthread_t t2;
    pthread_t t3;
    pthread_t t4;
    pthread_t t5;
    pthread_t t6;

    pthread_create(&t1, nullptr, consumer, &ringq);
    // pthread_create(&t2, nullptr, consumer, &ringq);
    // pthread_create(&t3, nullptr, consumer, &ringq);

    // pthread_create(&t4, nullptr, productor, &ringq);
    // pthread_create(&t5, nullptr, productor, &ringq);
    pthread_create(&t6, nullptr, productor, &ringq);

    pthread_join(t1, nullptr);
    // pthread_join(t2, nullptr);
    // pthread_join(t3, nullptr);
    // pthread_join(t4, nullptr);
    // pthread_join(t5, nullptr);
    pthread_join(t6, nullptr);

    return 0;
}

2,测试:

我们让生产者快,消费慢

看到没有,生产者生产满了是会等消费者消费了再去生产的。

我们让消费者快,生产者慢

看到没有,消费者会等待线生者生产的,当数据资源==0时,生产消费时互斥的,只能生产者生产,看到没有,当数据资源满了时,也只能消费者消费,看懂了没有。

 3,基于多线程

因为space_index++;data_index++:也不是原子操作,所以要加锁保护,其他都一样了。

ring_queue.hpp

#pragma once
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <semaphore.h>

const int cap_ = 10;
using namespace std;
template <class T>
class ring_queue
{

public:
    ring_queue(int cap = cap_)
        : ringq_(cap),
          spaceindex(0),
          dataindex(0)
    {
        // 初始化信号量
        sem_init(&space_sem_, 0, ringq_.size());
        sem_init(&data_sem_, 0, 0);
        // 初始化互斥锁
        pthread_mutex_init(&space_mutex, nullptr);
        pthread_mutex_init(&data_mutex, nullptr);
    }

    // 生产数据
    void push(const T &in)
    {
        // 申请信号量
        sem_wait(&space_sem_);

        pthread_mutex_lock(&space_mutex_);
        ringq_[spaceindex] = in;
        spaceindex++;
        spaceindex %= ringq_.size();
        pthread_mutex_unlock(&space_mutex_);
        // 空间资源用掉一个,数据资源就增加一个。
        sem_post(&data_sem_);
    }
    // 消费数据
    T pop()
    {

        // 申请数据资源,信号量
        sem_wait(&data_sem_);
        pthread_mutex_lock(&data_mutex_);
        T tmp = ringq_[dataindex];
        dataindex++;
        dataindex %= ringq_.size();
        pthread_mutex_unlock(&data_mutex_);

        // 消耗一个数据资源,空间资源就会多一个
        sem_post(&space_sem_);
        return tmp;
    }

private:
    vector<T> ringq_; // 数组模拟环形队列。
    sem_t space_sem_; // 记录空间资源个数
    sem_t data_sem_;  // 记录数据资源个数
    int spaceindex;   // 空间资源起始下标
    int dataindex;    // 数据资源起始下标

    pthread_mutex_t space_mutex_; // 多线程保护spaceindex++;
    pthread_mutex_t data_mutex_;  // 多线程保护dataindex++;
};

ring_test.cpp

 

#include <ctime>
#include "ring_queue.hpp"
#include <vector>
using namespace std;

void *consumer(void *args)
{
    ring_queue<int> *ringq = (ring_queue<int> *)args;

    while (true)
    {
        int tmp = ringq->pop();
        cout << "我是消费者,我的id:" << pthread_self() << "消费数据:" << tmp << endl;
        //sleep(1);
    }
}
void *productor(void *args)
{
    ring_queue<int> *ringq = (ring_queue<int> *)args;
    while (true)
    {
        int data = rand() % 50;
        ringq->push(data);
        cout << "我是生产者,我的id:" << pthread_self() << "生产数据:" <<data << endl;
sleep(1);
        // sleep(1);
    }
}
int main()
{

    srand(time(0));
    ring_queue<int> ringq(10);

    pthread_t t1;
    pthread_t t2;
    pthread_t t3;
    pthread_t t4;
    pthread_t t5;
    pthread_t t6;

    pthread_create(&t1, nullptr, consumer, &ringq);
    pthread_create(&t2, nullptr, consumer, &ringq);
    pthread_create(&t3, nullptr, consumer, &ringq);

    pthread_create(&t4, nullptr, productor, &ringq);
    pthread_create(&t5, nullptr, productor, &ringq);
    pthread_create(&t6, nullptr, productor, &ringq);

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    pthread_join(t4, nullptr);
    pthread_join(t5, nullptr);
    pthread_join(t6, nullptr);

    return 0;
}

4,测试 

这里的生产消费起始并发的,但是是广义上的并发,因为现实中生产数据,使用数据都是需要时间的。

三,代码链接

lyh_linux-test: linux代码练习。 - Gitee.com

 

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

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

相关文章

故障转移,服务发现,负载均衡所运用的连接池

没错&#xff0c;说的就是连接池&#xff0c;玩互联网架构&#xff0c;连接池是必须要掌握的。 什么是连接池&#xff1f; 创建与管理连接缓冲池的技术&#xff0c;本质是资源复用&#xff0c;不用频繁创建与销毁连接&#xff0c;能提高性能。 画外音&#xff1a;数据库连接池…

Sentinel-2 L2A数据导入ENVI

Sentinel-2 L2A数据导入ENVI前言0 首先对SNAP进行设置1 用SNAP对Sentinel-2数据重采样2 在ENVI中打开重采样后的Sentinel-2数据3 其实不用重采样也行&#xff0c;ENVI可以直接打开解压后的Ssentinel-2文件&#xff0c;只需要将解压后的MTD_MSIL2A.xml拖进ENVI即可前言 Sentine…

揭秘倚天实例背后的硬核实力

2022云栖大会&#xff0c;阿里巴巴宣布自研CPU倚天710已大规模应用&#xff0c;阿里云未来两年20%的新增算力将使用自研CPU。11月15日&#xff0c;倚天710云实例上线并正式进入大规模应用阶段&#xff0c;现已应用于阿里巴巴集团核心业务&#xff0c;并服务科学研究、智能手机行…

[附源码]JAVA毕业设计天津城建大学校友录管理系统(系统+LW)

[附源码]JAVA毕业设计天津城建大学校友录管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。…

Nvidia力作:医学图像分割网络

来源&#xff1a;投稿 作者&#xff1a;梦飞翔 编辑&#xff1a;学姐 引自Unetr: Transformers for 3d medical image segmentation 1.序言 本文将以Nvidia团队最近提出的一种新的医学图像分割网络作为切入点&#xff0c;结合所用开源数据集&#xff0c;为各位同学提供一份从…

杨校老师课堂之Spring框架面试题【开发工程师面试前必看】

1.spring 中都用到了哪些设计模式?2.spring 中有哪些核心模块?3.说一下你理解的 IOC 是什么?4.spring 中的 IOC 容器有哪些?有什么区别?5.那 BeanFactory 和 FactoryBean 又有什么区别?6.Repository、Service、Compent、Controller它们有什么区别?7.那么 DI 又是什么?8…

C#学习笔记一 委托、事件

C# 委托、事件 1、Action委托、Func委托 namespace DelegateExample {class Program{static void main(string[] args){Calculator calculatornew Calculator();//Action委托Action Calnew Action(calculator.Report);//直接调用函数Calculator.Report();//通过委托调用函数Ca…

艾美捷RPMI-1640培养基含L-谷氨酰胺的功能和研究

Roswell Park Memorial Institute (RPMI) 1640 培养基起初是为了悬浮培养人白血病单层细胞而开发的。RPMI 1640 培养基被发现适用于多种哺乳动物细胞&#xff0c;包括 HeLa 细胞、Jurkat 细胞、MCF-7 细胞、PC12 细胞、PBMC 细胞、星形胶质细胞和癌细胞。针对广泛的细胞培养应用…

阿里影业的稳健业绩来源:科技+内容塑造韧性,应对市场变化

随着《阿凡达&#xff1a;水之道》&#xff08;简称&#xff1a;《阿凡达2》&#xff09;预售佳绩的显现&#xff0c;电影业的复苏已然箭在弦上。 12月7日&#xff0c;《阿凡达2》正式开启预售&#xff0c;灯塔专业版数据显示&#xff0c;其预售开启4小时后&#xff0c;总票房…

【工作随笔】验证经验、维度

背景&#xff1a;目前负责模块的验证工作基本进展完毕&#xff0c;包括所有功能验证、场景覆盖、用例编写调试和仿真、功能覆盖率收集、sva检测时序等&#xff0c;在当前的进度上和开发、验证同时对我的工作进行了评审。 问题&#xff1a;在评审中间讨论到一个当前tc实现的问题…

五、卷积神经网络CNN7(图像卷积与反卷积)

图像卷积 首先给出一个输入输出结果那他是怎样计算的呢&#xff1f; 卷积的时候需要对卷积核进行 180 的旋转&#xff0c;同时卷积核中心与需计算的图像像素对齐&#xff0c;输出结构为中心对齐像素的一个新的像素值&#xff0c;计算例子如下&#xff1a;这样计算出左上角(即第…

基于Dijkstra和A算法的机器人路径规划附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

JAVA SCRIPT设计模式--行为型--设计模式之Observer观察者模式(19)

JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能&#xff0c;所以不可能像C&#xff0c;JAVA等面向对象语言一样严谨&#xff0c;大部分程序都附上了JAVA SCRIPT代码&#xff0c;代码只是实现了设计模式的主体功能&#xff0c;不代…

Python图像识别实战(一):实现按比例随机抽取图像移动到另一文件夹

前面我介绍了可视化的一些方法以及机器学习在预测方面的应用&#xff0c;分为分类问题&#xff08;预测值是离散型&#xff09;和回归问题&#xff08;预测值是连续型&#xff09;&#xff08;具体见之前的文章&#xff09;。 从本期开始&#xff0c;我将做一个关于图像识别的…

Nacos集群搭建

1、下载nacos http://t.csdn.cn/ejfu9 2、配置Nacos 进入nacos的conf目录&#xff0c;修改配置文件cluster.conf.example&#xff0c;重命名为cluster.conf&#xff1a; 然后添加内容&#xff1a; 添加的内容是你要启动的多台nacos的IP和端口 127.0.0.1:8845 127.0.0.1:8846…

如何批量注册推特账号

Twitter推特账号怎么注册&#xff1f;相信国内好多朋友都被推特注册卡住&#xff0c;不知怎么注册twitter账号&#xff0c;由于国内限制的问题&#xff0c;推特账号注册比以前更麻烦了&#xff0c;本文将详细讲解Twitter怎么注册&#xff0c;Twitter (推特)是一个广受欢迎的社交…

【C#基础学习】第十五章、结构

目录 结构 1.结构的构造函数 1.1 实例构造函数 1.2 静态构造函数 1.3 总结 2.结构体作为返回值和参数 结构 结构的定义&#xff1a;结构是一种可以由程序员自定义的密封的值类型。 结构与类的区别&#xff1a;结构与类类似&#xff0c;它们都有自己的数据成员和函数成员。…

Nginx篇之实现反向代理和端口转发

一、前言 在正式生产环境中&#xff0c;web服务器、反向代理服务器的选择大都会选择nginx&#xff0c;确实&#xff0c;在常见的高并发场景下&#xff0c;nginx能够支持以万为单位的并发请求量&#xff0c;并且服务性能稳定&#xff0c;应用极为广泛。 二、反向代理含义 反向代…

【LeetCode_字符串_中心扩散 】5. 最长回文子串

目录考察点第一次&#xff1a;2022年12月8日10:29:05解题思路代码展示&#xff1a;中心扩散题目描述5. 最长回文子串 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。 示例 1&#xff1a; 输入&#xff1a;s "babad" 输出&#xff1a;"bab" 解…

高通平台开发系列讲解(Camera篇)新增GC8034摄像头步骤

文章目录 一、新增配置文件二、配置摄像头三、设置效果文件四、修改设备树五、修改用户空间驱动程序沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要介绍高通平台新增摄像头步骤。 一、新增配置文件 在vendor/qcom/proprietary/common/config/device-vendor.…