【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃个人主页 :阿然成长日记 👈点击可跳转
📆 个人专栏: 🔹数据结构与算法🔹C语言进阶🔹C++🔹Liunx
🚩 不能则学,不知则问,耻于问人,决无长进
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍
文章目录
- 前言:
- 一、什么是临界区和临界资源?
- 二、SystemV信号量引出
- 三、什么是SystemV信号量?
- 四、 SystemV信号量的创建和控制以及操作
- 1.semget()函数:
- 2.semctl()函数:
- 3.semop()函数:
前言:
上一篇博客讲解了System V共享内存,在最后说它的缺点时提到,他没有提供进程同步机制,那么为了弥补这个缺点,所以引入了信号量sem机制。
一、什么是临界区和临界资源?
-
临界资源:多个进程共同使用的一份资源,例如共享内存就是一个临界资源
-
临界区:不同进程内部,访问临界资源的那段代码
二、SystemV信号量引出
- 打个比方:这场电影一共有五十个位置,设置一个信号量n,n = 50;看电影的人必须买票,买一张票信号量n就会减一,当n=0时,也就代表资源已经耗尽,没有位置了。但是如果有人退票的话,n会加1。买了票才能进入观影。
相应的,每一个进程想进入临界资源,访问临界资源的一部分,不能让进程直接去使用临界资源(不能让用户直接去电影院抢占座位),而是先得申请 信号量(先得买票)。
这样说的话,我们只需要一个int型的变量就可做到计数器的功能了,那还大费周章的提出一个信号量干嘛呢?
1.不是局部变量
- 这个变量肯定不是局部变量,那么使用一个全局变量可以吗?
2.不是全局变量
- 如果使用全局变量,父子进程在申请信号量时,会发生写时拷贝,导致这个变量父子进程各自一份,也不太行。
3.不在共享内存中
- 那就使用最近刚刚学习的共享内存不就好了吗。仔细思考也不可以。
- 首先共享内存也就是说变量直接存储在内存中。我们创建的几个程序执行时是需要将指令放入cpu中进行执行。
- 假设只看这个共享区的变量n,它的随着一个进程执行过程如下
1.将内存中的数据n加载到cpu的寄存器
2.n–(分析&&执行指令)
3.将cpu修改完毕的n写回内存。 - 一个进程执行流在执行的时候,在任何时刻都可能被切换 , 被切换的时候,会带走自己的上下文数据(包括n),然后再被切回来的时候,再把自己的上下文数据写入到cpu的寄存器中,继续执行。
- 这样就有了一个问题:
假设有10个进程,分别为1,2,3,4…,9,10,而临界资源一共只有5份,所以信号量n也为5.
假设1先申请信号量,但运气不好执行完第一步,就被切走了,然后2,3,4,5,6都正常申请了信号量,此时信号量已经为0,后面7到10的进程都不能再申请了。
但此时1号又开始继续执行,由于第一次进来时n是5,继续执行第2,3步,n–为4,然后再写回到内存,此时n从0变成了4,这不就差了吗,明明都没有资源了,结果信号量成了4,后面的进程又可以继续申请,这样肯定就出错了。
所以n减减时,因为时序问题导致n有中间状态,可能导致数据不一致、但如果n只有一行汇编,那么该操作就是原子的!
4.提出System V信号量
所以就提出了信号量机制
三、什么是SystemV信号量?
信号量的本质是:是一个描述临界资源的计数器
System V信号量是一种在操作系统中提供的进程间通信(IPC)机制,用于实现进程之间的同步和互斥。它通过对计数器进行操作来控制资源的访问。
System V信号量由一个整型的标识符(semaphore identifier)来标识,每个标识符对应着一个信号量集合(semaphore set)。信号量集合中可以包含多个单独的信号量,每个信号量都有一个非负整数值。
四、 SystemV信号量的创建和控制以及操作
分别对一个semget()、semctl()和semop()
头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
1.semget()函数:
首先回顾一下ftok():
ftok()函数生成key
头文件:
#include <sys/types.h>
#include <sys/ipc.h>
格式:
key_t ftok(const char *pathname, int proj_id);
- 参数:
pathname指针:一个字符串,用于标识一个文件的路径名。通常会选择一个已经存在的文件,因为 ftok() 函数将使用该文件的inode编号和 proj_id 参数通过算法来生成键值key。
proj_id:一个整数,作为用于生成键的项目标识号。该参数通常取一个非负整数。 - 返回值:成功则返回生成的键值,否则返回-1。
格式:
int semget(key_t key, int nsems, int semflg);
参数:
-
key:唯一key值,用于标识要创建或获取的信号量集合。
key值可以使用ftok()获取 -
nsems:指定信号量集合中信号量的数量。你想创建几个信号量。可以想象成一个数组。 -
semflg:标志参数,用于指定信号量的创建方式和访问权限。有下面两个
选项
| IPC_CREATE | 创建共享内存,如果底层已经存在,则获取并返回;如果不存在,则创建共享内存然后再返回, |
|---|---|
| IPC_CREATE | IPC_EXCL | 如果底层不存在,则创建共享内存并返回;如果底层存在,则出错返回。言外之意,如果返回成功,那么一定是一个全新的内存块! |
使用:
通过指定一个键值和其他参数,调用semget()函数可以创建一个新的信号量集合,或者获取一个已经存在的信号量集合。
返回值:
返回值是一个信号量标识符(semaphore identifier),它用于后续对信号量集合的控制和操作
注意理清一个概念:semget()可以一次申请多个信号量(n1,n2.n3,),其中一个信号量n1就是一个计数器
2.semctl()函数:
int semctl(int semid, int semnum, int cmd, ...);
参数:
- semid:信号量标识符,用于指定要操作的信号量集合。
- semnum:注意与seget()区分清楚。指定具体的信号量在集合中的
索引,用于标识要操作的信号量。 - cmd:执行的控制命令,用于指定具体的操作。
- arg:根据不同的命令,需要提供的参数。
下面是semctl函数cmd形参说明表
| 命令 | 解 释 |
|---|---|
| IPC_STAT | 从信号量集上检索semid_ds结构,并存到semun联合体参数的成员buf的地址中 |
| IPC_SET | 设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值 |
IPC_RMID | 从内核中删除信号量集合 |
| GETALL | 从信号量集合中获得所有信号量的值,并把其整数值存到semun联合体成员的一个指针数组中 |
| GETNCNT | 返回当前等待资源的进程个数 |
| GETPID | 返回最后一个执行系统调用semop()进程的PID |
| GETVAL | 返回信号量集合内单个信号量的值 |
| GETZCNT | 返回当前等待100%资源利用的进程个数 |
| SETALL | 与GETALL正好相反 |
| SETVAL | 用联合体中val成员的值设置信号量集合中单个信号量的值 |
用法:
semctl()函数用于控制和管理信号量集合。
可以通过指定不同的控制命令(cmd)来实现不同的操作,例如设置信号量的初始值、获取或改变信号量的值,以及删除信号量集合等。
具体的参数(如arg)根据不同的命令而有所不同。
3.semop()函数:
int semop(int semid, struct sembuf *sops, unsigned nsops);
参数:
- semid:信号量标识符,用于指定要操作的信号量集合。由seget()获取
- sops:指向一个sembuf结构体数组的指针,包含了一组操作。此结构的具体说明如下:(
里面的注释很重呀)
struct sembuf {short semnum; 指定要操作的信号量在集合中的索引,从0开始计数。short op;指定要执行的操作。
如果sem_op的值大于0,则表示进行V(释放)操作,即增加信号量的值。
如果sem_op的值小于0,则表示进行P(等待)操作,即减少信号量的值。
如果sem_op的值等于0,则表示进行Z(零)操作,如果信号量的值为0,则等待。该操作通常用于同步操作,以等待某个特定条件的发生。short flag; 用于指定操作的标志。
IPC_NOWAIT:如果无法进行操作(例如信号量的值为0且sem_op为负数),则立即返回,不进行等待。
SEM_UNDO:系统在进程意外终止时,会自动撤销该进程对信号量的操作,以避免死锁。};
- nsops:指定操作的数量。
作用: 用于对指定信号量集【semid】当中的指定数量的信号量【nsops:常常设置为1】,对它做操作【sembuf *sops】
相关文章:
【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
JAVA预编译简单理解
目录 一、JSP预编译 二、JDBC预编译 一、JSP预编译 JSP(JavaServer Pages)是一种动态网页技术标准,它允许将Java代码嵌入到HTML页面中。当第一次请求一个JSP页面时,Web服务器(如Tomcat)会将JSP页面转换成一…...
nvm 管理多版本 node
1、下载 先不安装node 下载 nvm 1.1.10-setup.zip 解压:nvm:https://nvm.uihtm.com/ 新建nodejs/node、nodejs/nvm文件夹用于存放node版本和nvm安装路径 安装nvm:上述链接有安装教程 查看是否安装成功:重新打开cmd 输入 nvm nv…...
C++中的多重继承和虚继承:横向继承、纵向继承和联合继承;虚继承
多重继承 A.横向多重继承: B.纵向多重继承: C.联合多重继承: 因为 single 和 waiter 都继承了一个 worker 组件,因此 SingingWaiter 将包含两个 worker 组件,那么将派生类对象的地址赋给基类指针将出现二义性 那么如何…...
利用node连接mongodb实现一个小型后端服务系统demo
http 请求 实现get请求数据库数据;实现添加数据实现编辑数据实现删除数据实现导出txt文件、Excel文件实现查询数据库数据并利用导出为excel文件 node 版本 16.16.0 node 版本 18.16.0 会连接 MongoDB 数据库错误。 Connected to MongoDB failed MongoServerSele…...
大数据面试题之数据库(3)
数据库有必要建索引吗? MySQL缺点? 什么是脏读?怎么解决? 为什么要有三大范式,建数据库时一定要遵循吗? 数据库一般对哪些列建立索引?索引的数据结构? MySOL中索引的建立需要考虑哪些问题 关系型数据库与非关系型数据库区别 MySQL与Redis区别 …...
升级之道:精通Conda的自我升级艺术
升级之道:精通Conda的自我升级艺术 引言 Conda是Python和其他科学计算语言的强大包管理器,它不仅管理着包的安装和依赖,还负责自身的更新。随着开源社区的不断发展,Conda定期发布新版本以修复已知问题、增加新功能和提高性能。本…...
领导者视角:识别系统问题的信号
作为企业的领导者,有时候我们面对的不仅是表面的小问题,而是根深蒂固的系统性问题。如果您发现以下症状,可能就是时候深入挖掘了: 1、资源消耗大:一个看似小的问题,解决起来却不断耗费大量资源。 2、反复无…...
CentOS7二进制安装和YUM安装mongodb,服务器无法安装5.0以上的 mongodb 数据库报错 Illegal instruction
文章目录 MongoDB 安装二进制安装YUM 安装 Tips:1、MongoDB安装问题2、MongoDB登录3、MongoDB排序时内存大小限制和创建索引4、创建用户5、Java yaml使用密码连接mongodb6、MongoDB增删改查 MongoDB 安装 二进制安装 [rootmysql5-7 mongodb-6.0.4]# cat start.sh #!/bin/bash…...
AI的前世今生:从理论起源到未来展望
引言 人工智能(AI)作为一门交叉学科,涵盖了计算机科学、数学、认知科学、神经科学等多个领域,已经成为现代科技的重要组成部分。本文将回顾AI的发展历程,从理论起源到当代应用,再到未来展望,为…...
C# list集合元素去重的几种方法
一、使用使用HashSet去重 List<int> dataSource new List<int>() { 1, 2, 2, 3, 4, 5, 5, 7, 8, 10 }; //源数组中共有10个元素HashSet<int> uniqueData new HashSet<int>(dataSource); //去重之后为8个//输出uniqueData元素为:1,2,3,4,5…...
WritableStream()写入流,将数字或字符流,写入你需要的地方
WritableStream有两个对象参数: 第一个必选,用于配置一些写入流时的钩子; 第二个可选,用于配置一些chunk入队和队列控制的策略; 第二个参数的策略(利用ByteLengthQueuingStrategy【按字节计量】和CountQueu…...
RK3568平台(opencv篇)opencv处理图像视频
一.读取图像文件并展示 灰度图像: 灰度图需要用 8 位二进制来表示,取值范围是 0-255。用 0 表示 0(黑色), 用 255 表示 1(白色),取值越大表示该点越亮。 RGB 彩色图像:…...
4. kvm存储虚拟化
kvm存储虚拟化 一、命令行工具管理虚拟磁盘1、查看虚拟磁盘2、添加磁盘3、删除磁盘 二、qcow2格式的磁盘文件1、创建磁盘文件2、差量镜像/快速创建虚机2.1 创建差量镜像2.2 准备配置文件2.3 创建虚拟机2.4 批量部署虚拟机 三、存储池 storage pool1、类型2、在线迁移2.1 规划后…...
uniapp+vue3嵌入Markdown格式
使用的库是towxml 第一步:下载源文件,那么可以git clone,也可以直接下载压缩包 git clone https://github.com/sbfkcel/towxml.git 第二步:设置文件夹内的config.js,可以选择自己需要的格式 第三步:安装…...
处理成二维数组对象
const objects [] let checkboxvalue [{ name: 名字1 }, { name: 名字2 }] let data [{ value: 值1, id: id1 }, { value: 值2, id: id2 }]let arr [] checkboxvalue.map((item, index) > {// data[index].name item.namearr.unshift({ contractName: item.name, list:…...
智能汽车网络安全笔记
汽车五大域 动力底盘、车身控制、智能座舱、智能网联和高级辅助驾驶五大域 国外汽车安全法规标准 汽车网络安全管理体系(CSMS) CSMS指的是管理汽车的网络威胁和风险,并保护车辆免受网络攻击的组织过程和管理系统 安全验证和安全测试 8…...
web 网络安全
Web网络安全是网络安全的一个重要分支,专注于保护Web应用程序、服务和网站免受各种网络威胁。学习Web网络安全涉及多个层面的知识和技能,以下是一些主要的学习领域: 一、XSS攻击 全称::Cross Site Script (跨站脚本&a…...
Vue 3与Pinia:下一代状态管理的探索
引言 随着Vue 3的推出,Pinia应运而生,成为官方推荐的状态管理库,旨在替代Vuex。Pinia与Vuex相比,带来了以下主要区别和优势: 更简洁的API:Pinia的API设计更加直观和简洁,易于理解和使用。更好…...
《植物大战僵尸杂交版》2.2版本:全新内容与下载指南
《植物大战僵尸杂交版》2.2版本已经火热更新,带来了一系列令人兴奋的新玩法和调整,为这款经典的塔防游戏注入了新的活力。如果你是《植物大战僵尸》系列的忠实粉丝,那么这个版本绝对值得你一探究竟。 2.2版本更新亮点 新增看星星玩法 这个新…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
