当前位置: 首页 > news >正文

【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()函数讲解

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …...

JAVA预编译简单理解

目录 一、JSP预编译 二、JDBC预编译 一、JSP预编译 JSP&#xff08;JavaServer Pages&#xff09;是一种动态网页技术标准&#xff0c;它允许将Java代码嵌入到HTML页面中。当第一次请求一个JSP页面时&#xff0c;Web服务器&#xff08;如Tomcat&#xff09;会将JSP页面转换成一…...

nvm 管理多版本 node

1、下载 先不安装node 下载 nvm 1.1.10-setup.zip 解压&#xff1a;nvm&#xff1a;https://nvm.uihtm.com/ 新建nodejs/node、nodejs/nvm文件夹用于存放node版本和nvm安装路径 安装nvm&#xff1a;上述链接有安装教程 查看是否安装成功&#xff1a;重新打开cmd 输入 nvm nv…...

C++中的多重继承和虚继承:横向继承、纵向继承和联合继承;虚继承

多重继承 A.横向多重继承&#xff1a; B.纵向多重继承&#xff1a; C.联合多重继承&#xff1a; 因为 single 和 waiter 都继承了一个 worker 组件&#xff0c;因此 SingingWaiter 将包含两个 worker 组件&#xff0c;那么将派生类对象的地址赋给基类指针将出现二义性 那么如何…...

利用node连接mongodb实现一个小型后端服务系统demo

http 请求 实现get请求数据库数据&#xff1b;实现添加数据实现编辑数据实现删除数据实现导出txt文件、Excel文件实现查询数据库数据并利用导出为excel文件 node 版本 16.16.0 node 版本 18.16.0 会连接 MongoDB 数据库错误。 Connected to MongoDB failed MongoServerSele…...

大数据面试题之数据库(3)

数据库有必要建索引吗? MySQL缺点? 什么是脏读?怎么解决? 为什么要有三大范式&#xff0c;建数据库时一定要遵循吗? 数据库一般对哪些列建立索引?索引的数据结构? MySOL中索引的建立需要考虑哪些问题 关系型数据库与非关系型数据库区别 MySQL与Redis区别 …...

升级之道:精通Conda的自我升级艺术

升级之道&#xff1a;精通Conda的自我升级艺术 引言 Conda是Python和其他科学计算语言的强大包管理器&#xff0c;它不仅管理着包的安装和依赖&#xff0c;还负责自身的更新。随着开源社区的不断发展&#xff0c;Conda定期发布新版本以修复已知问题、增加新功能和提高性能。本…...

领导者视角:识别系统问题的信号

作为企业的领导者&#xff0c;有时候我们面对的不仅是表面的小问题&#xff0c;而是根深蒂固的系统性问题。如果您发现以下症状&#xff0c;可能就是时候深入挖掘了&#xff1a; 1、资源消耗大&#xff1a;一个看似小的问题&#xff0c;解决起来却不断耗费大量资源。 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的前世今生:从理论起源到未来展望

引言 人工智能&#xff08;AI&#xff09;作为一门交叉学科&#xff0c;涵盖了计算机科学、数学、认知科学、神经科学等多个领域&#xff0c;已经成为现代科技的重要组成部分。本文将回顾AI的发展历程&#xff0c;从理论起源到当代应用&#xff0c;再到未来展望&#xff0c;为…...

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元素为&#xff1a;1,2,3,4,5…...

WritableStream()写入流,将数字或字符流,写入你需要的地方

WritableStream有两个对象参数&#xff1a; 第一个必选&#xff0c;用于配置一些写入流时的钩子&#xff1b; 第二个可选&#xff0c;用于配置一些chunk入队和队列控制的策略&#xff1b; 第二个参数的策略&#xff08;利用ByteLengthQueuingStrategy【按字节计量】和CountQueu…...

RK3568平台(opencv篇)opencv处理图像视频

一.读取图像文件并展示 灰度图像&#xff1a; 灰度图需要用 8 位二进制来表示&#xff0c;取值范围是 0-255。用 0 表示 0&#xff08;黑色&#xff09;&#xff0c; 用 255 表示 1&#xff08;白色&#xff09;&#xff0c;取值越大表示该点越亮。 RGB 彩色图像&#xff1a;…...

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 第一步&#xff1a;下载源文件&#xff0c;那么可以git clone&#xff0c;也可以直接下载压缩包 git clone https://github.com/sbfkcel/towxml.git 第二步&#xff1a;设置文件夹内的config.js&#xff0c;可以选择自己需要的格式 第三步&#xff1a;安装…...

处理成二维数组对象

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:…...

智能汽车网络安全笔记

汽车五大域 动力底盘、车身控制、智能座舱、智能网联和高级辅助驾驶五大域 国外汽车安全法规标准 汽车网络安全管理体系&#xff08;CSMS&#xff09; CSMS指的是管理汽车的网络威胁和风险&#xff0c;并保护车辆免受网络攻击的组织过程和管理系统 安全验证和安全测试 8…...

web 网络安全

Web网络安全是网络安全的一个重要分支&#xff0c;专注于保护Web应用程序、服务和网站免受各种网络威胁。学习Web网络安全涉及多个层面的知识和技能&#xff0c;以下是一些主要的学习领域&#xff1a; 一、XSS攻击 全称:&#xff1a;Cross Site Script &#xff08;跨站脚本&a…...

Vue 3与Pinia:下一代状态管理的探索

引言 随着Vue 3的推出&#xff0c;Pinia应运而生&#xff0c;成为官方推荐的状态管理库&#xff0c;旨在替代Vuex。Pinia与Vuex相比&#xff0c;带来了以下主要区别和优势&#xff1a; 更简洁的API&#xff1a;Pinia的API设计更加直观和简洁&#xff0c;易于理解和使用。更好…...

《植物大战僵尸杂交版》2.2版本:全新内容与下载指南

《植物大战僵尸杂交版》2.2版本已经火热更新&#xff0c;带来了一系列令人兴奋的新玩法和调整&#xff0c;为这款经典的塔防游戏注入了新的活力。如果你是《植物大战僵尸》系列的忠实粉丝&#xff0c;那么这个版本绝对值得你一探究竟。 2.2版本更新亮点 新增看星星玩法 这个新…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

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步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...