41 POSIX信号量

POSIX信号量

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

31节说了信号量,信号量的本质是一个计数器。将共享资源从一个整体划分为很多不部分,就和电影院的座位一样,信号量就是资源总共的数量。信号量的获取就是一种对资源的预定机制,申请信号量成功,资源数量–,当数量为0时,申请失败。申请和释放就是PV操作。在线程里,存储数据的部分就是共享资源,用信号量来管理它,描述可以存多少数据,把资源是否就绪放在了临界区之外,申请信号量时,就已经间接的判断了,在PV操作之间访问资源,如果获得了信号量,就表明一定有资源可以适用,不需要判断资源是否还有

相关函数

初始化信号量

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
pshared:0表示线程间共享,非零表示进程间共享
value:信号量初始值

销毁信号量

int sem_destroy(sem_t *sem);

等待信号量

功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem);

发布信号量

功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);

环形队列的生产消费模型

环形队列采用数组模拟,模运算模拟特性
环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过计数器或者标记位来判断满或者空,另外也可以预留一个空的位置,作为满的状态
但是我们现在有信号量这个计数器,就很简单的实现多线程同步过程

在这里插入图片描述

环形队列本质是一个数组,用圆的方式模拟头尾相接。C和P分别是生产者和消费者的下标,刚开始两者都在同一位置,当环形队列为空的时候,一定是P先生产,放入一个数据后往后挪动一下,然后消费者获取数据,获得数据后也往后挪动一下,这时P和C又处于同一位置。

P关注的是还剩余多少空间,初始值为最大存储N,每生产一个这个值就会–,定义一个空间信号量,SpaceSem:N,
C关注的是还有多少剩余数据,初始值为0,取走一个就–,定义一个数据信号量,DataSem:0
根据上面,生产者生产数据,增加DataSem,减少SpaceSem,消费者消费,增加SpaceSem,减少DataSem

P和C什么时候会出现在同一位置,一定是空或者满,不空或不满的时候,它们两个可以同时访问队列,因为它们只需要维护好属于自己的信号量和下标,就不会产生干扰

满足条件
上产消费整个过程就像一个追逐游戏,生产者先走,消费者在后面追,环形队列的生成消费模型必须满足这三个条件
1.指向同一个位置时,只能有一个人访问。
空:生产者访问,放入数据
满:消费者访问,取出数据
2.消费者不能超过生产者生产的速度,生产者生产5个,不能消费5个以上
3.生产者不能套两个圈,生产者在生产满所有位置的时候,不能继续移动了

实现

类的设计
首先需要一个数组存放数据,生产和消费两个下标,剩余空间和当前数据两个信号量,多生产多消费同一时间只能有一个访问存储空间,所以需要两把锁
push的时候先申请空间信号量,申请到了放入数据移动下标,下标是多生产者的共享资源,所以这些访问需要上锁,信号量的操作是原子的,不需要上锁。消费也同样

#pragma once
#include <pthread.h>
#include <vector>
#include <semaphore.h>

static const int defaultcap = 5;
template <class T>
class RingQueue
{
public:
    RingQueue(int cap = defaultcap)
    :_que(defaultcap)
    {
        _pstep = 0;
        _cstep = 0;
        _maxcap = cap;

        sem_init(&_sem_sapace, 0, cap);
        sem_init(&_sem_data, 0, 0);

        pthread_mutex_init(&_pmutex, nullptr);
        pthread_mutex_init(&_cmutex, nullptr);

    }

    void push(const T& x)
    {
       //P
       sem_wait(&_sem_sapace);
       //信号量不需要上锁
       pthread_mutex_lock(&_pmutex);
       _que[_pstep] = x;
       //位置后移,维持环形
       _pstep++;
       _pstep %= _maxcap;
       pthread_mutex_unlock(&_pmutex);
       //V操作
       sem_post(&_sem_data);
    }

//消费
    void pop(T* out)
    {
        //P
       sem_wait(&_sem_data);
       pthread_mutex_lock(&_cmutex);
       *out = _que[_cstep];  
       //维持环形
       _cstep++;
       _cstep %= _maxcap;
       pthread_mutex_unlock(&_cmutex);   
       // V操作
       sem_post(&_sem_sapace);
    }

    ~RingQueue()
    {
        sem_destroy(&_sem_sapace);
        sem_destroy(&_sem_data);

        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);
    }

private:
    std::vector<T> _que;
    int _maxcap;

    int _pstep;  //生产者下标
    int _cstep;  //消费者下标

    sem_t _sem_sapace;
    sem_t _sem_data;

    pthread_mutex_t _pmutex;
    pthread_mutex_t _cmutex;
};

线程部分和上一节基本一样

#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <ctime>
#include "blockqueue.hpp"
#include "task.hpp"
#include "RingQuene.hpp"
#include "Ring.hpp"

void *produce(void *bk)
{
    RingQueue<task>* block = static_cast<RingQueue<task>*>(bk);
    
    while (true)
    {
        int x1 = rand() % 10;
        usleep(10);
        int x2 = rand() % 10 + 1;
        char op = g_op[rand() % 4];
        task t(x1, x2, op);

        //生产
        printf("%p生产任务:%s\n", pthread_self(), t.gettask().c_str());
        block->push(t);
        sleep(2);
    }
}

void* consume(void* bk)
{
    RingQueue<task>* block = static_cast<RingQueue<task>*>(bk);
    while (true)
    {
        //消费
        task n;
        block->pop(&n);
        n.run();
        printf("%p完成任务:%s\n", pthread_self(), n.getresult().c_str());
        //sleep(1);
    }
}

int main()
{
    srand(time(NULL));
    RingQueue<task>* block = new RingQueue<task>();
    pthread_t ptid[3], ctid[5];
    for (int i = 0; i < 3; i++)
    {
        pthread_create(&ptid[i], nullptr, produce, block);
    }

    for (int i = 0; i < 5; i++)
    {
        pthread_create(&ctid[i], nullptr, consume, block);
    }

     for (int i = 0; i < 3; i++)
    {
        pthread_join(ptid[i], nullptr);
    }

    for (int i = 0; i < 5; i++)
    {
        pthread_join(ctid[i], nullptr);
    } 
    

    delete block;
    return 0;
}

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

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

相关文章

可视化大屏应用场景:智慧安防,保驾护航

hello&#xff0c;我是大千UI工场&#xff0c;本篇分享智慧安防的大屏设计&#xff0c;关注我们&#xff0c;学习N多UI干货&#xff0c;有设计需求&#xff0c;我们也可以接单。 实时监控与预警 可视化大屏可以将安防系统中的监控画面、报警信息、传感器数据等实时展示在大屏上…

【word技巧】Word目录如何设置为对齐?

Word文档的目录有些在修改之后无法对齐&#xff0c;大家是不是会自己手动删除省略号&#xff1f;今天分享一个方法&#xff0c;设置之后&#xff0c;tab一键对齐目录。 先选中目录&#xff0c;然后点击段落设置界面&#xff0c;选择左下角的【制表位】 然后将制表位置设置为【…

蓝桥杯练习系统(算法训练)ALGO-947 贫穷的城市

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 某城市有n个小镇&#xff0c;编号是1~n。由于贫穷和缺乏城市规划的人才&#xff0c;每个小镇有且仅有一段单向的公路通往别…

一机游领航旅游智慧化浪潮:借助前沿智能设备,革新旅游服务效率,构建高效便捷、生态友好的旅游服务新纪元,开启智慧旅游新时代

目录 一、引言 二、一机游的定义与特点 &#xff08;一&#xff09;一机游的定义 &#xff08;二&#xff09;一机游的特点 三、智能设备在旅游服务中的应用 &#xff08;一&#xff09;旅游前的信息查询与预订支付 &#xff08;二&#xff09;旅游中的导航导览与互动体…

SHOW ME THE CODE - 面向对象程序设计之 - 接口隔离原则(ISP)

SHOW ME THE CODE - 面向对象设计系列 1 SHOW ME THE CODE - 面向对象基本概念2 SHOW ME THE CODE - 面向对象程序设计之 - 单一职责原则(SRP)3 SHOW ME THE CODE - 面向对象程序设计之 - 开闭原则&#xff08;OCP&#xff09;4 SHOW ME THE CODE - 面向对象程序设计之 - 里氏…

C语言实验-学生信息管理系统

按以下菜单界面编写学生信息管理系统&#xff1b; 1&#xff09;录入学生信息首先输入学生人数&#xff0c;然后根据学生人数开辟动态数组&#xff1b; 2&#xff09;学生信息包括学号、姓名、性别、三门课成绩、总分&#xff1b;其中学号、姓名、 性别、三门课成绩是需要从键盘…

用git上传本地文件到github

两种方式&#xff1a;都需要git软件&#xff08;1&#xff09;VScode上传 &#xff08;2&#xff09;直接命令行&#xff0c;后者不需要VScode软件 &#xff08;1&#xff09;vscode 上传非常方便&#xff0c;前提是下载好了vscode和git软件 1 在项目空白处右击&#xff0c;弹…

ReentrantReadWriteLock类

为了有了ReentrantLock还需要ReentrantReadWriteLock ReentrantReadWriteLock是一个读写锁&#xff0c;它允许多个读操作同时进行&#xff0c;但在写操作时会阻止其他所有读和写操作。这种锁特别适合于读取远多于写入的场景&#xff0c;因为它可以提高并发性而不会牺牲数据一致…

华为OD机试 - 小扇和小船的数字游戏 - 二进制(Java 2024 C卷 200分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

VsCode | 修改首页启动页 Logo

VsCode | 修改首页启动页 Logo 最终效果&#xff1a; 插件的安装 先安装插件 Custom CSS and JS Loader 插件配置 Ctrl Shift P 输入 打开用户设置&#xff0c;在末尾添加 "vscode_custom_css.imports": [""]下载 Logo 下载 Logo 点我下载 引入…

SDB2F3 1.5A,高达28V输出1.2MHz升压转换器芯片IC

一般说明 该SDB2F3是一个恒定的频率&#xff0c;5针SOT23用于小型低功率应用的电流模式升压转换器。 该SDB2F3开关在1.2MHz&#xff0c;并允许使用微小&#xff0c;低成本的电容器和电感2毫米或更少的高度。内部软启动的结果在小浪涌电流和延长电池寿命。 该SDB2F3工作从…

string底层浅析

char简单易用,但是string是万金油 char *b "123"; string a{"123"};a是不是地址 发现a是地址 a的地址是不是和a[0]地址重合 #include<iostream> #include<cstring> using namespace std; int main() {string a{ "123" };char g[…

Pytorch分布式train——pytorch.distributed.launch V.S. torchrun

1. 较早的pytorch.distributed.launch python -m torch.distributed.launch --nproc_per_node4 --nnodes1 --node_rank0 train.py --args XXX 参数解析&#xff1a; nnodes&#xff1a;节点&#xff08;主机&#xff09;的数量&#xff0c;通常一个节点对应一个主机 node_rank…

探索动态内存开辟的奥秘

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱博客 所属栏目&#xff1a;C语言 前言 开始之前&#xff0c;我们先来了解一下C/C中程序内存区域划分。 在C/C程序中&#xff0c;内存区域通常被划分为以下几个部分&#xff1a; 1.栈&…

漏洞挖掘之某厂商OAuth2.0认证缺陷

0x00 前言 文章中的项目地址统一修改为: a.test.com 保护厂商也保护自己 0x01 OAuth2.0 经常出现的地方 1&#xff1a;网站登录处 2&#xff1a;社交帐号绑定处 0x02 某厂商绑定微博请求包 0x02.1 请求包1&#xff1a; Request: GET https://www.a.test.com/users/auth/weibo?…

C++设计模式-创建型设计模式

设计模式 设计模式是什么 设计模式是指在软件开发中&#xff0c;经过验证的&#xff0c;用于解决在特定环境下&#xff0c;重复出现的&#xff0c;特定问题的解决方案&#xff1b;其实就是解决问题的固定套路。但是要慎用设计模式&#xff0c;有一定的工程代码量之后用它比较…

Hdfs小文件治理策略以及治理经验

小文件是 Hadoop 集群运维中的常见挑战&#xff0c;尤其对于大规模运行的集群来说可谓至关重要。如果处理不好&#xff0c;可能会导致许多并发症。Hadoop集群本质是为了TB,PB规模的数据存储和计算因运而生的。为啥大数据开发都说小文件的治理重要&#xff0c;说HDFS 存储小文件…

Python字符串常用方法(全网最细,仅此一份)

🥇作者简介:CSDN内容合伙人、新星计划第三季Python赛道Top1 🔥本文已收录于Python系列专栏: 👉Python从入门到精通 💬订阅专栏后可私信博主进入Python学习交流群,进群可领取Python180G全栈视频教程以及Python相关电子书合集 😊私信未回可以加V:hacker0327 备注P…

Word文件后缀

Word文件后缀 .docx文件为Microsoft Word文档后缀名&#xff0c;基于XML文件格式 .dotm为Word启用了宏的模板 .dotx为Word模板 .doc为Word97-2003文档&#xff0c;二进制文件格式 参考链接 Word、Excel 和 PowerPoint 的文件格式参考 Learn Microsoft

u盘格式化后电脑读不出来怎么办?u盘格式化的东西还能恢复吗

随着科技的快速发展&#xff0c;U盘已成为我们日常生活和工作中不可或缺的数据存储工具。然而&#xff0c;有时我们可能会遇到U盘格式化后电脑无法读取的情况&#xff0c;或是误格式化导致重要数据丢失。面对这些问题&#xff0c;我们该如何应对&#xff1f;本文将为您详细解答…