【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版本更新亮点 新增看星星玩法 这个新…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
