Linux系统编程系列之进程间通信-信号量组
一、什么是信号量组
信号量组是信号量的一种, 是system-V三种IPC对象之一,是进程间通信的一种方式。
二、信号量组的特性
信号量组不是用来传输数据的,而是作为“旗语”,用来协调各进程或者线程工作的。信号量组可以一次性在其内部设置多个信号量,而信号量本质上是一个数字,用来表征一种资源的数量,当多个进程或者线程争夺这些稀缺资源的时候,信号量用来保证他们合理地,秩序地使用这些资源,而不会陷入逻辑谬误之中。
三、信号量组的使用场景
1、生产者-消费者模式
2、进程间同步
3、进程间通信
四、函数API接口
1、创建或者打开SEM对象
// 创建或打开SEM对象 int semget(key_t key, int nsems, int semflg);// 接口说明:参数key:SEM对象键值参数nsems:信号量组内的信号量元素个数参数semflg:创建选项IPC_CREAT:如果该key对应的信号量不存在,则创建IPC_EXCL:如果该key对应的信号量已存在,则报错mode:信号量的访问权限创建信号量时,还受到以下系统信息的影响: 1、SEMMNI:系统中信号量的总数最大值 2、SEMMSL:每个信号量中信号量元素的个数最大值 3、SEMMNS:系统中所有信号量中的信号量元素的总数最大值
2、P/V操作
对于信号量而言,最重要的作用是用来表征对应资源的数量,所谓的P/V操作就是对资源数量进行 +n/-n 操作,既然只是个加减法,那么为什么不使用普通的整型数据呢,原因是:
(1)、整型数据的加减操作不具有原子性,即操作可能被中断
(2)、普通加减法无法提供阻塞特性,而申请资源不可得时应该进入阻塞
// PV操作 int semop(int semid, struct sembuf *sops, size_t nsops);// 接口说明参数semid:SEM对象ID参数sops:PV操作结构体sembuf数组参数nsops:PV操作结构体数组元素个数返回值:成功 0,失败 -1PV操作结构体定义如下: struct sembuf {unsigned short sem_num; // 信号量元素序号(数组下标)short sem_op; // 操作参数short sem_flg; // 操作选项 }根据sem_op的数值,信号量操作分成3种情况:(1)当sem_op大于0时:当进行V操作(释放),即信号量元素的值(semval)将会被加上sem_op的值。如果SEM_UNDO被设置了,那么该V操作将会被系统记录,V操作永远不会导致进程阻塞。(2)当sem_op等于0时:进行等零操作,如果此时semval恰好为零,则semop()立即成功返回,否则如果IPC_NOWAIT被设置,则立即出错返回并将errno设置为EAGAIN,否则将使得进程进入睡眠,直到以下情况发生:[1]semval变为0[2]信号量被删除 (将导致semop()出错退出,错误码为EIDRM)[3]收到信号 (将导致semop()出错退出,错误码为EINTR)(3)当sem_op小于0时(申请资源):进行P操作,即信号量元素的值(semval)将会被减去sem_op的绝对值。如果semval大于或等于sem_op的绝对值,则semop()立即成功返回,semval的值将减去sem_op的绝对值,并且如果SEM_UNDO被设置了,那么该P操作将会被系统记录。 如果semval小于sem_op的绝对值并且设置了IPC_NOWAIT,那么semop()将会出错返回且将错误码置为EAGIN,否则将使得进程进入睡眠,直到以下情况发生:[1]semval的值变得大于或者等于sem_op的绝对值[2]信号量被删除 (将导致semop()出错退出,错误码为EIDRM)[3]收到信号 (将导致semop()出错退出,错误码为EINTR)
3、删除SEM对象
// 删除SEM对象 int semctl(int semid, int semnum, int cmd, ...);// 接口说明semid:信号量组的IDsemnum:信号量组内的元素序号(从0开始)cmd;操作命令字IPC_STAT:获取信号量组的一些信息,放入结构体semid_ds中IPC_SET:将结构体semid_ds中指定的信息,设置到信号量组中IPC_RMID:删除指定的信号量组GETALL:获取所有信号量元素的值SETALL:设置所有信号量元素的值GETVAL:获取第semnum个信号量元素的值SETVAL:设置第semnum个信号量的值
五、信号量组使用步骤
1、使用ftok(),获取IPC通信对象KEY值
2、使用semget(),获取SEM对象ID,并判断是否需要进行初始化
3、使用semop(),进行P/V操作,操作信号量组
4、使用命令或者函数删除信号量组
六、案例
使用信号量组结合共享内存的方式完成两个进程的数据收发。
// 信号量组结合共享内存的案例#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include <errno.h>// 编译时分两个版本,一个直接编译,另外一个把A的宏定义注释,把B的宏定义展开 #define A 1 //#define B 1 // 编译第二版本时,请去掉前面的注释,同时注释A的宏定义// 注意A进程的P信号量与B进程的V信号量相对应,所以要修改信号量序号的下标 #if A #define DATA_P_NUM 0 #define DATA_V_NUM 1 #define SPACE_P_NUM 2 #define SPACE_V_NUM 3#elif B #define DATA_P_NUM 1 #define DATA_V_NUM 0 #define SPACE_P_NUM 3 #define SPACE_V_NUM 2 #endif#define SEM_NUM 4 // 4个信号量 #define SEM_KEY 0x01 #define SHM_KEY 0x02 #define SHM_SIZE 4096int sem_id = -1; // 映射的虚拟地址 char *shm_addr = NULL;// 信号量组初始化 int sem_init(void) {// 1、获取IPC对象的KEY值key_t sem_key = ftok("./", SEM_KEY);if(sem_key == -1){perror("ftok fail");return -1;}// 2、获取SEM对象的ID, 申请4个信号量sem_id = semget(sem_key, SEM_NUM, IPC_EXCL | IPC_CREAT | 0666);// 如果已经存在就不需要初始化,直接获取if(sem_id == -1 && errno == EEXIST){// 直接获取SEM对象IDsem_id = semget(sem_key, SEM_NUM, IPC_CREAT | 0666);if(sem_id == -1){perror("semget fail");return -1;}}// 不存在则需要在获取SEM对象ID后进行初始化else if(sem_id > 0){sem_id = semget(sem_key, SEM_NUM, IPC_CREAT | 0666);if(sem_id == -1){perror("semget fail");return -1;}// 初始化semctl(sem_id, DATA_P_NUM, SETVAL, 0); // 初始值为0semctl(sem_id, DATA_V_NUM, SETVAL, 0); // 初始值为0semctl(sem_id, SPACE_P_NUM, SETVAL, 1); // 初始值为1semctl(sem_id, SPACE_V_NUM, SETVAL, 1); // 初始值为1}else{perror("semget fail");return -1;} }// 共享内存初始化 int shm_init(void) {// 1、获取KEY值key_t shm_key = ftok("./", 1);if(shm_key == -1){perror("ftok fail");return -1;}// 2、指定共享内存,获取共享内存对象IDint shm_id = shmget(shm_key, SHM_SIZE, IPC_CREAT | 0666);if(shm_id == -1){perror("shmget fail");return -1;}// 3、映射共享内存shm_addr = (char*)shmat(shm_id, NULL, 0);if(shm_addr == (void*)-1){perror("shmat fail");return -1;} }int main(int argc, char *argv[]) {int ret = 0;ret = sem_init();if(ret == -1){return -1;}ret = shm_init();if(ret == -1){return -1;}// 接收数据, 数据-1struct sembuf Data_P = {.sem_flg = SEM_UNDO,.sem_num = DATA_P_NUM,.sem_op = -1};// 发送数据, 数据+1struct sembuf Data_V = {.sem_flg = SEM_UNDO,.sem_num = DATA_V_NUM,.sem_op = 1};// 占用空间, 空间-1struct sembuf Space_P = {.sem_flg = SEM_UNDO,.sem_num = SPACE_P_NUM,.sem_op = -1};// 释放空间 空间+1struct sembuf Space_V = {.sem_flg = SEM_UNDO,.sem_num = SPACE_V_NUM,.sem_op = 1};pid_t pid = fork();// 父进程负责发送数据if(pid > 0){while(1){// 申请空间,P操作printf("wait Space_P...\n");semop(sem_id, &Space_P, 1);printf("get Space_P\n");printf("please input data: \n");fgets(shm_addr, SHM_SIZE, stdin);// 释放数据,V操作semop(sem_id, &Data_V, 1);printf("set Data_V, send data success\n");}}// 子进程负责接收数据else if(pid == 0){while(1){// 申请数据,P操作printf("wait Data_P...\n");semop(sem_id, &Data_P, 1);printf("read Data: %s", shm_addr);memset(shm_addr, 0, SHM_SIZE);// 释放空间,V操作semop(sem_id, &Space_V, 1);printf("set Space_V\n");}}else{perror("fork fail");return -1;}return 0; }
注:编译时,编译两个版本,一个直接编译,另外一个需要注释A的宏定义,然后展开B的宏定义后才能编译第二个版本。
分析:具体的PV操作这里不讲解,为什么要申请4个信号量,这个要讲明白的话,很难,有空再出另外一篇博客讲,敬请留意。
七、总结
信号量组只能作为一种信号,不能用来传递数据,多用于使用P/V操作的场景,可以同时操作多个信号量,但是要实现传递数据,必须配合其他通信方式,如共享内存。可以结合案例来加深对信号量组的理解。
相关文章:
Linux系统编程系列之进程间通信-信号量组
一、什么是信号量组 信号量组是信号量的一种, 是system-V三种IPC对象之一,是进程间通信的一种方式。 二、信号量组的特性 信号量组不是用来传输数据的,而是作为“旗语”,用来协调各进程或者线程工作的。信号量组可以一次性在其内…...
centos 6使用yum安装软件
1. 执行以下命令,查看当前操作系统 CentOS 版本。 cat /etc/centos-release返回结果如下图所示,则说明当前操作系统版本为 CentOS 6.9。 2. 执行以下命令,编辑 CentOS-Base.repo 和CentOS-Epel.repo文件。 vim /etc/yum.repos.d/CentOS-Bas…...
maven无法下载时的解决方法——笔记
右键项目然后点击创建setting.xml(因为现在创建了,所以没显示了,可以直接点击打开setting.xml) 然后添加 <mirror><id>nexus-aliyun</id><mirrorOf>*,!jeecg,!jeecg-snapshots</mirrorOf><name…...
Java Spring Boot 开发框架
Spring Boot是一种基于Java编程语言的开发框架,它的目标是简化Java应用程序的开发过程。Spring Boot提供了一种快速、易于使用的方式来创建独立的、生产级别的Java应用程序。本文将介绍Spring Boot的特性、优势以及如何使用它来开发高效、可靠的应用程序。 一、简介…...
Pytorch学习记录-1-张量
1. 张量 (Tensor): 数学中指的是多维数组; torch.Tensor data: 被封装的 Tensor dtype: 张量的数据类型 shape: 张量的形状 device: 张量所在的设备,GPU/CPU requires_grad: 指示是否需要计算梯度 grad: data 的梯度 grad_fn: 创建 Tensor 的 Functio…...
paddle2.3-基于联邦学习实现FedAVg算法-CNN
目录 1. 联邦学习介绍 2. 实验流程 3. 数据加载 4. 模型构建 5. 数据采样函数 6. 模型训练 1. 联邦学习介绍 联邦学习是一种分布式机器学习方法,中心节点为server(服务器),各分支节点为本地的client(设备&#…...
nuiapp保存canvas绘图
要保存一个 Canvas 绘图,可以使用以下步骤: 获取 Canvas 元素和其绘图上下文: var canvas document.getElementById("myCanvas"); var ctx canvas.getContext("2d");使用 Canvas 绘图 API 绘制图形。 使用 toDataUR…...
Object.defineProperty()方法详解,了解vue2的数据代理
假期第一篇,对于基础的知识点,我感觉自己还是很薄弱的。 趁着假期,再去复习一遍 Object.defineProperty(),对于这个方法,更多的还是停留在面试的时候,面试官问你vue2和vue3区别的时候,不免要提一提这个方法…...
Linux 磁盘管理
Linux 系统的磁盘管理直接关系到整个系统的性能表现。磁盘管理常用三个命令为: df、du 和 fdisk。 df df(英文全称:disk free)。df 命令用于显示磁盘空间的使用情况,包括文件系统的挂载点、总容量、已用空间、可用空间…...
大数据与人工智能的未来已来
大数据与人工智能的定义 大数据: 大数据指的是规模庞大、复杂性高、多样性丰富的数据集合。这些数据通常无法通过传统的数据库管理工具来捕获、存储、管理和处理。大数据的特点包括"3V": 大量(Volume):大数…...
【AI视野·今日Robot 机器人论文速览 第四十一期】Tue, 26 Sep 2023
AI视野今日CS.Robotics 机器人学论文速览 Tue, 26 Sep 2023 Totally 73 papers 👉上期速览✈更多精彩请移步主页 Daily Robotics Papers Extreme Parkour with Legged Robots Authors Xuxin Cheng, Kexin Shi, Ananye Agarwal, Deepak Pathak人类可以通过以高度动态…...
[NOIP2012 提高组] 开车旅行
[NOIP2012 提高组] 开车旅行 题目描述 小 A \text{A} A 和小 B \text{B} B 决定利用假期外出旅行,他们将想去的城市从 $1 $ 到 n n n 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 …...
数据库设计流程---以案例熟悉
案例名字:宠物商店系统 课程来源:点击跳转 信息->概念模型->数据模型->数据库结构模型 将现实世界中的信息转换为信息世界的概念模型(E-R模型) 业务逻辑 构建 E-R 图 确定三个实体:用户、商品、订单...
Miniconda创建paddlepaddle环境
1、conda env list 2、conda create --name paddle_env python3.8 --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ 3、activate paddle_env 4、python -m pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple 5、pip install "p…...
postgresql实现单主单从
实现步骤 1.主库创建一个有复制权限的用户 CREATE ROLE 用户名login # 有登录权限的角色即是用户replication #复制权限 encrypted password 密码;2.主库配置开放从库外部访问权限 修改 pg_hba.conf 文件 (相当于开放防火墙) # 类型 数据库 …...
提取PDF数据:Documents for PDF ( GcPdf )
在当今数据驱动的世界中,从 PDF 文档中无缝提取结构化表格数据已成为开发人员的一项关键任务。借助GrapeCity Documents for PDF ( GcPdf ),您可以使用 C# 以编程方式轻松解锁这些 PDF 中隐藏的信息宝藏。 考虑一下 PDF(最常用的文档格式之一…...
adb连接切换到模拟器端口
查看连接状态 adb devices出现以下情况 C:\Users\22560>adb devices List of devices attached 127.0.0.1:5555 offline emulator-5554 device可以发现我们想要连接的雷电模拟器的5555端口目前没有连接,只有emulator-5554被连接了,此时我们需要关…...
为何每个开发者都在谈论Go?
目录 一、引言Go的历史回顾关键时间节点 使用场景Go的语言地位技术社群与企业支持资源投入和生态系统 二、简洁的语法结构基本组成元素变量声明与初始化代码示例 类型推断函数与返回值代码示例输出 接口与结构体:组合而非继承错误处理:明确而不是异常小结…...
【Leetcode】 501. 二叉搜索树中的众数
给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。 如果树中有不止一个众数,可以按 任意顺序 返回。 假定 BST 满足如下定义…...
怎样给Ubuntu系统安装vmware-tools
首先我要告诉你:Ubuntu无法安装vmware-tools,之所以这么些是因为我一开始也是这样认为的,vmware-tools是给Windows系统准备的我认为,毕竟Windows占有率远远高于Linux,这也可以理解。 那么怎么样实现Ubuntu虚拟机跟Wind…...
DDS信号发生器波形发生器VHDL
名称:DDS信号发生器波形发生器 软件:Quartus 语言:VHDL 要求: 在EDA平台中使用VHDL语言为工具,设计一个常见信号发生电路,要求: 1. 能够产生锯齿波,方波,三角波&…...
Python3操作SQLite3创建表主键自增长|CRUD基本操作
Win11查看安装的Python路径及安装的库 Python PEP8 代码规范常见问题及解决方案 Python3操作MySQL8.XX创建表|CRUD基本操作 Python3操作SQLite3创建表主键自增长|CRUD基本操作 anaconda3最新版安装|使用详情|Error: Please select a valid Python interpreter Python函数绘…...
B. Comparison String
题目: 样例: 输入 4 4 <<>> 4 >><< 5 >>>>> 7 <><><><输出 3 3 6 2 思路: 由题意,条件是 又因为要使用尽可能少的数字,这是一道贪心题,所以…...
python端口扫描
扫描所有端口 import socket, threading, os, timedef port_thread(ip, start, step, timeout):for port in range(start, start step):s socket.socket()s.settimeout(timeout)try:s.connect((ip, port))print(f"port[{port}] 可用")except Exception as e:# pri…...
国庆第二天
#include<th.h>#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__",__LINE__);\perror(msg);\ }while(0)#define PORT 6666 #define IP "192.168.2.3"//键盘输入事件 int serverkeyboard(fd_set readfds) {char buf[128] "";int sndfd -…...
Java安全之servlet内存马分析
目录 前言 什么是中间键 了解jsp的本质 理解servlet运行机制 servlet的生命周期 Tomcat总体架构 查看Context 的源码 servlet内存马实现 参考 前言 php和jsp一句话马我想大家都知道,早先就听小伙伴说过一句话木马已经过时了,现在是内存马的天下…...
2023年第二十届中国研究生数学建模竞赛总结与分享
今天是国庆节,祝祖国繁荣富强。正好也学习不下去,就想着写写博客,总结一下自己在参加2023年第20届中国研究生数学建模比赛的一些感受。 目录 1.基本介绍 2.比赛分享 1.基本介绍 1. 竞赛时间:竞赛定于2023年9月22日8:00至2023年9…...
Web前端-Vue2+Vue3基础入门到实战项目-Day1(初始Vue, Vue指令, 小黑记事本)
Web前端-Vue2Vue3基础入门到实战项目-Day1 Vue快速上手创建一个Vue实例插值表达式Vue响应式特性 Vue指令指令初识 和 v-htmlv-show 和 v-ifv-else 和 v-else-ifv-on内联语句methods处理函数调用传参 v-bind案例 - 波仔的学习之旅v-forv-for基本使用案例 - 小黑的书架v-for的key…...
Sentinel学习(2)——sentinel的使用,引入依赖和配置 对消费者进行流控 对生产者进行熔断降级
前言 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 本篇博客介绍sentinel的使用&#x…...
springboot 简单配置mongodb多数据源
准备工作: 本地mongodb一个创建两个数据库 student 和 student-two 所需jar包: # springboot基于的版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId>&l…...
外贸公司的网站建设模板/网站收录查询爱站
1、启动 NODE_ENVproduction node index.js 如果出现启动不了的情况,在该命令加sudo sudo NODE_ENVproduction node index.js 2、备份数据以及切换数据库 备份数据 进入http://your.domain/labs 操作很简单,export 导出 json文件 3、切换数据库 主要修改…...
绍兴网站制作多少钱/爱站小工具计算器
1. 打开ppt,将即将打印的部分编辑好,再 另存为—>文件格式请选择windows 图元文件,保存好即可! 2.打开word,使用word的宏,编辑这些图片的宏代码: (1) 点击“工具”…...
山东天成水利建设有限公司网站/seo工资一般多少
如果你有一个苹果,我有一个苹果我们交换以后,还是一人一个苹果但如果你有一种思想,我有一种思想我们交换以后,每个人便拥有了两种思想; 转载于:https://www.cnblogs.com/JoinZhang/archive/2006/01/03/310096.html...
免费空间访问/seo搜索优化推广
【IT168 专稿】存储是目前IT产业发展的一大热点,而RAID技术是构造高性能、海量存储的基础技术,也是构建网络存储的基础技术。专家认为,磁盘阵列的性能优势得益于磁盘运行的并行性,提高设备运行并行度可以提高磁盘的性能和数据安全…...
wordpress多用户商城/数据分析师要学什么
本文收集整理关于python如何解一元二次方程的相关议题,使用内容导航快速到达。 内容导航: Q1:python 使用try except解一元二次方程问题 12345678910111213141516171819报错UnboundLocalError:localvariableareferencedbeforeassignment这个报…...
做进行网站推广赚钱/竞价推广什么意思
在用多线程的时候,里面要用到Spring注入服务层,或者是逻辑层的时候,一般是注入不进去的。具体原因应该是线程启动时没有用到Spring实例不池。所以注入的变量值都为null。 如果在run方法里面加载application.xml,来取得bean时&…...