《Linux从练气到飞升》No.30 深入理解 POSIX 信号量与生产消费模型

🕺作者: 主页

我的专栏
C语言从0到1
探秘C++
数据结构从0到1
探秘Linux
菜鸟刷题集

😘欢迎关注:👍点赞🙌收藏✍️留言

🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢阅读!!!

文章目录

    • 前言
    • 1 POSIX信号量相关概念
    • 2 POSIX信号量相关函数
    • 3 基于环形队列的生产消费模型

前言

在多线程编程领域,理解 POSIX 信号量的概念和相关函数是至关重要的。POSIX 信号量作为一种重要的同步原语,可以帮助我们在多线程环境中实现线程之间的协调与同步,从而确保数据的一致性和避免竞争条件的发生。

本篇博客旨在深入探讨 POSIX 信号量的基本概念和相关函数,帮助读者全面理解这一关键的并发编程工具。通过本文的学习,读者将能够掌握如何灵活地运用 POSIX 信号量来构建并发程序,提高程序的性能和可靠性。让我们一起深入探索 POSIX 信号量的奥秘,为多线程编程的世界增添新的智慧与力量。

1 POSIX信号量相关概念

POSIX信号量是什么?

信号量的本质是一个计数器,是用来描述临界资源有效的计数器

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。
当多个线程想要获取信号量的时候,都会对信号量当中的资源计数器进行减一操作。
如果初始化信号量的资源计数器的值为1表示当前只有一个资源,这就意味着只有一个线程在同一时刻可以获取到信号量。
如果想要实现线程同步,初始化信号量的资源计数器的值就不必为1了,它可以根据需要设置

  • 如果大于0则表示还有多少资源可以使用
  • 等于0则表示没有资源可以使用
  • 小于0则表示有多少线程在等待资源。

2 POSIX信号量相关函数

  1. 信号量初始化
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:sem_t: 信号量的类型sem: 传入待要初始化的信号量pshared: 0 表示线程间共享,非0表示进程间共享value:信号量初始值
  1. 信号量销毁
int sem_destroy(sem_t *sem);
参数:sem:待销毁的信号量
  1. 信号量等待
功能:等待信号量,会将信号量的值减1int sem_wait(sem_t *sem); //P()
  1. 信号量发布
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1int sem_post(sem_t *sem);//V()

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

  • 上一个生产者-消费者的例子是基于queue的,其空间可以动态分配,现在基于固定大小的环形队列重写这个程序(POSIX信号量)。

image.png

  • 环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过加计数器或者标记位来判断满或者空。另外也可以预留一个空的位置,作为满的状态

image.png
但是我们现在有信号量这个计数器,就很简单的进行多线程间的同步过程
实现代码如下:
RingQueue.cc

#pragma#include<iostream>
#include<unistd.h>
#include<vector>
#include<semaphore.h>
#include<stdlib.h>#define NUM 10class RingQueue
{
private:std::vector<int> v;int _cap;//容量sem_t sem_product;//生产者sem_t sem_consume;//消费者int p_index;//生产者索引int c_index;//消费者索引public:RingQueue(int cap=NUM):_cap(cap),v(cap){sem_init(&sem_product,0,cap);sem_init(&sem_consume,0,0);p_index = 0;c_index = 0;}~RingQueue(){sem_destroy(&sem_product);sem_destroy(&sem_consume);}void put(const int&in){sem_wait(&sem_product);v[p_index] = in;p_index++;p_index = p_index%NUM;sem_post(&sem_consume);}void get(int &out){sem_wait(&sem_consume);out = v[c_index];c_index++;c_index = c_index%NUM;sem_post(&sem_product);}
};

main.cc

#include"RingQueue.cc"
using namespace std;void* Consumer(void* arg){RingQueue *bq = (RingQueue*)arg;int data;while(1){bq->get(data);cout<<"I am "<<pthread_self()<<" is consumer : "<<data<<endl;}
}void* Product(void* arg){RingQueue* bq = (RingQueue*)arg;srand((unsigned int)time(NULL));while(1){int data = rand()%100;bq->put(data);cout<<"I am "<<pthread_self()<<" is product "<<data<<endl;sleep(1);}
}int main()
{RingQueue* pq = new RingQueue();pthread_t c;pthread_t p;pthread_create(&c,NULL,Consumer,(void*)pq);pthread_create(&p,NULL,Product,(void*)pq);pthread_join(c,NULL);pthread_join(p,NULL);return 0;
}

makefile

main:main.ccg++ -o $@ $^ -lpthread
.PHONY:
clean:rm -f main

结果:
可以观察到生产一个消费一个
image.png

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

德思特案例 | Skydel GNSS仿真引擎助力多所高校实现GNSS仿真测试教育

来源&#xff1a;德思特测量测试 德思特案例 | Skydel GNSS仿真引擎助力多所高校实现GNSS仿真测试教育 目前高校研究机构很难拥有用于定位、导航和定时&#xff08;PNT&#xff09;的测试和模拟工具&#xff0c;卫星导航相关的教育基本都是通过教科书或基于Matlab代码编程进行研…

11.22文心中国行走进厦门,把握大模型时代的产业新机遇

11月22日&#xff0c;文心中国行将走进厦门。届时&#xff0c;政府、高校及企业的相关专家将现场分享AI和大模型最新进展&#xff0c;从人工智能政策解读&#xff0c;到大模型底层技术&#xff0c;再到产教融合下的空间感知与计算&#xff0c;产业创新应用洞察及实践案例等等&a…

eclipse启动无法找到类(自定义监听器)

一.报错 二.排查 1.首先检查代码是否有问题 本人报错是找不到监听器&#xff0c;故检查监听器的代码和web.xml文件是否有问题 public class DoorListener implements ServletContextListener 监听器是否继承并实现ServletContextListener中的方法。 web.xml中&#xff1a; &…

Java 21:最新特性、性能改进和语言发展

文章目录 模式匹配和模式变量新的记录类型生产者接口本地类型推断的扩展新的垃圾收集器动态CDS档案G1垃圾收集器的增强Java语言的持续发展性能改进和JEPJava 21的部署和使用Java 21的生态系统结语 &#x1f389;欢迎来到Java学习路线专栏~Java 21&#xff1a;最新特性、性能改进…

【YOLOv7/YOLOv5系列算法改进NO.47】改进激活函数为GELU

文章目录 前言一、解决问题二、基本原理三、​添加方法四、总结 前言 作为当前先进的深度学习目标检测算法YOLOv7&#xff0c;已经集合了大量的trick&#xff0c;但是还是有提高和改进的空间&#xff0c;针对具体应用场景下的检测难点&#xff0c;可以不同的改进方法。此后的系…

如何选择数据恢复软件?前 5 名免费数据恢复软件榜单供参考

我们都知道开源数据恢复软件有很多优点。搜索免费解决方案的用户会被其可用性所吸引&#xff0c;而那些拥有足够技术技能的用户可能会被其定制软件以满足其需求的灵活性所吸引。在本文中&#xff0c;我们为您挑选了最好的开源数据恢复软件&#xff0c;并将尝试回答开源软件是否…

项目架构设计说明书编制

目录 项目名称 1 简介 1.1 目的 1.2 范围 1.3 术语及缩略语 1.4 引用文档 1.5 概述 2 构架表示方式 3 构架目标和约束 4 用例视图 4.1 用例实现 5 逻辑视图 5.1 概述 5.2 在构架方面具有重要意义的设计包 5.3 内部接口设计与协作机制 5.4 对外接…

物理驱动深度学习方法总结

一、物理驱动深度学习方法总结 现有博主更新物理驱动深度学方法总体介绍 二、 PINN介绍 PINN综述Blog介绍&#xff1a;内嵌物理知识神经网络 &#xff08;Physics Informed Neural Network&#xff0c;简称PINN&#xff09; 是一种科学机器在传统数值领域的应用方法&…

宏集干货 | 手把手教你通过CODESYS V3进行PLC编程(三)

来源&#xff1a;宏集科技 工业物联网 宏集干货 | 手把手教你通过CODESYS V3进行PLC编程&#xff08;三&#xff09; 教程背景 通过之前的教程&#xff0c;我们已经为大家演示了宏集MC-Prime控制器的连接、试运行和CODESYS的安装&#xff0c;并创建了一个计数器项目。在本期教…

cocos2dx中,将png图片打包plist图集,使用什么工具呢?

cocos2dx中&#xff0c;将png图片打包plist图集&#xff0c;使用什么工具呢&#xff1f;小编这里推荐一款免费的图集打包工具&#xff0c;pngPackerGUI_V2.0&#xff0c;此软件是在pngpacker_V1.1软件基础之后&#xff0c;开发的界面化操作软件&#xff0c;方便不太懂命令行的小…

JVM-HotSpot虚拟机对象探秘

目录 一、对象的实例化 &#xff08;一&#xff09;创建对象的方式 &#xff08;二&#xff09;创建对象的步骤 二、对象的内存布局 &#xff08;一&#xff09;对象头 &#xff08;二&#xff09;实例数据 &#xff08;三&#xff09;对齐填充 三、 对象的访问定位 &…

如何在Linux上搭建本地Docker Registry并实现远程连接

Linux 本地 Docker Registry本地镜像仓库远程连接 文章目录 Linux 本地 Docker Registry本地镜像仓库远程连接1. 部署Docker Registry2. 本地测试推送镜像3. Linux 安装cpolar4. 配置Docker Registry公网访问地址5. 公网远程推送Docker Registry6. 固定Docker Registry公网地址…