【Linux】进程间通信——信号量

让大家久等啦,本期我们来讲讲Linux系统中的信号量

目录

一、引入

二、认识信号量

2.1 信号量的概念

2.2 信号量的内核结构

三、关于信号量的接口

3.1 semget

3.2 ipcs -s

3.3 ipcrm -s

3.4 semctl

3.5 semop

四、理解IPC


一、引入

在开始之前我们先来认识几个概念:

公共资源:多个进程或线程(至于线程我们后面会详细讲解)都可以访问和使用的资源

互斥:任何一个时刻,都只允许一个执行流在进行共享资源的访问

临界资源:任何一个时刻,都只允许一个执行流在进行访问的共享资源

临界区:通过代码访问临界资源的代码

原子性:要么不做,要么做完(没有正在做的状态),只有两种确定状态的属性

二、认识信号量

2.1 信号量的概念

有了上面的概念,我们下面来引入信号量的概念:

当我们想要访问临界资源时,由于其独有的特性,我们需要知道想要访问的临界资源是否在被别的执行流访问,即使此时没有被其他的执行流访问,也并不能确定我们是否能访问该临界资源(可能该时间段被其他的执行流预定了)

所以为了管理好临界资源的调配,引入了一个整数来描述资源数量,这个东西就被称为:信号量(信号灯)

照我们现在的理解就可以将信号量看做为一个int count,其本质就是一个计数器!

下面模拟一下我们使用代码访问临界资源的场景:

我们可以看到只要是要访问临界资源的代码主要可以分为两部分:临界区和非临界区

● 当进程运行到临界区时,必须要遵守访问临界资源的规则:和信号量打交道

● 在进入临界区访问资源之前先要申请信号量,一旦信号量申请成功,该进程未来就一定可以拿到一个子资源,同时该信号量就会进行--操作;如果没有申请成功,该进程将会进入阻塞状态等待资源(上面这个过程被称为P(荷兰语:Passeren)操作

● 当我们的进程访问完临界资源后,一旦出了临界区就要释放信号量资源,同时该信号量就会进行++操作,一旦信号量进行++就表示对应的资源进行了归还(上面这个过程被称为V(荷兰语:Vrijgeven)操作

● 但是整个过程有一个问题:那必须让所以的进程看到同一个信号量啊,那这样信号量本身不就变成了共享资源了吗?那共享资源时需要被维护的,那谁来维护信号量呢?

这就需要保证信号量是经过特殊处理的,其--和++操作一定要有原子性,不能说信号量正在加或者正在减

● 那两个进程能看到同一个信号量吗?我们知道子进程会继承父进程中的环境变量,所以它们一定是可以看到同一份信号量的,但是一旦对其进行P或者V操作会发生写时拷贝啊,这样子进程之间不就各自玩各自的了吗?

所以我们要让不同的进程之间共同使用同一个信号量,最终导致信号量要被归纳到进程间通信(IPC)

 

2.2 信号量的内核结构

在Linux中信号量是这样被定义的:

The semid_ds data structure is defined in <sys/sem.h> as follows:struct semid_ds {struct ipc_perm sem_perm;  /* Ownership and permissions */time_t          sem_otime; /* Last semop time */time_t          sem_ctime; /* Last change time */unsigned long   sem_nsems; /* No. of semaphores in set */};The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):struct ipc_perm {key_t          __key; /* Key supplied to semget(2) */uid_t          uid;   /* Effective UID of owner */gid_t          gid;   /* Effective GID of owner */uid_t          cuid;  /* Effective UID of creator */gid_t          cgid;  /* Effective GID of creator */unsigned short mode;  /* Permissions */unsigned short __seq; /* Sequence number */};

但是上面展示出来的只是对于用户层面的,其内核还有其他更复杂的结构

我们只需了解用户使用层面最重要的结构即可,其他的结构控制就交给操作系统处理

三、关于信号量的接口

3.1 semget

我们可以使用semget函数(包含在头文件<sys/types.h>和<sys/ipc.h>中)创建或访问一个信号量集(多个不同的信号量可以被作为一个集合)

● key:这是一个键(key),用于标识信号量集。通过提供一个键值,你可以创建一个新的信号量集合或访问一个现有的集合。特殊值 IPC_PRIVATE 可被用作键来创建一个新的私有信号量集,该集只能被调用者的进程及其子进程访问。对于非私有信号量,通常会使用ftok()函数基于一个文件路径和一个项目标识符来生成一个唯一的键值。

● nsems:这是信号量集中信号量的数量。当创建一个新的信号量集时,这个参数指定集合中应该有多少个信号量。如果你正在访问一个现有的集合,这个值应该设为0。

● semflg:这是一个标志集,用于确定操作的行为,该参数可以是多个标志的按位 OR 组合,这些标志提供了对权限的控制以及其他选项。此外,semflg还可以包含权限位,这些位通常是八进制的数值,比如0600,代表只有创建者有读写权限,0666则表示所有用户都有读写权限。

    通常使用的标志有:

   - IPC_CREAT:如果指定的信号量集不存在,那么创建它。否则,返回现有的信号量集。
   - IPC_EXCL:与 IPC_CREAT 一起使用时,如果信号量集已存在,则返回错误。防止不知不觉中访问现有的信号量集。
   - IPC_NOWAIT:在某些系统 V IPC 操作中使用,用于指示非阻塞操作,虽然在semget函数中它不起作用,但对于后续对信号量的操作可能有影响。

该函数的返回值是信号量集的标识符(非负整数),如果失败则返回-1,同时设置errno以指示发生了什么错误。

3.2 ipcs -s

在Linux系统中我们可以使用ipcs -s指令获取当前各个信号量的关键信息

例如:

其中:

  • key:信号量集(semaphore set)的标识符(具有唯一性)
  • semids:信号量数组的唯一标识符。
  • owner:拥有该信号量的用户。
  • perms:表示权限的八进制数,接近于文件系统的权限,规定谁可以访问这些信号量。
  • nsems:信号量组中信号量的数量。

3.3 ipcrm -s

我们可以使用指令:ipcrm -s后面跟上一个semids(信号量数组的唯一标识符),删除指定的信号量

3.4 semctl

如果我们想在程序中删除信号量,可以使用semctl函数

其中: 

  • semid: 这是信号量集的标识符(semaphore set identifier),它是由 semget 系统调用返回的,用于标识要操作的信号量集。
  • semnum: 这是要操作的信号量集中的信号量的序号,从 0 开始计数。对于只影响单个信号量的操作,这个参数指明了信号量集中信号量的索引。
  • cmd: 这是一个命令参数,它决定了要对信号量执行哪种类型的操作。一些常用的命令包括 SETVAL(设置信号量的值)、GETVAL(获取信号量的当前值)、IPC_RMID(删除信号量集)等。
  • ...: 这是一个可变参数列表,其内容会根据 cmd 参数的值而变化(和printf最后一个参数使用方式相同)。比如,如果cmd 是 SETVAL,则需要提供一个 union semun 类型的参数,其中包含将要设置的新值。

3.5 semop

提到信号量就不得不说说pv操作了,在Linux系统下我们可以使用semop接口在 Linux 操作系统中,semop 接口用于对信号量集(semaphore set)中的一个或多个信号量(semaphores)执行操作。信号量是系统 V 信号量的组成部分,通常用于进程间的同步和互斥。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>int semop(int semid, struct sembuf *sops, unsigned nsops);
  • semid: 这是一个整数,表示信号量集的标识符,它是通过之前的 semget 系统调用创建或获取的
  • sops: 是一个指向一个或多个 sembuf 结构体数组的指针。每个结构体指定了要对单个信号量进行的操作。(该参数需要我们自己在外部定义传入)
  • nsops: 表示 sops 数组中 sembuf 结构体的数量,即一次系统调用中要执行的操作数量

sembuf结构体的定义如下所示:

struct sembuf {unsigned short  sem_num;  /* 信号量集合中信号量的索引 */short   sem_op;   /* 信号量操作 */short   sem_flg;  /* 操作标志 */
};

sem_num: 指定要操作的信号量在信号量集中的索引

sem_op: 指定要执行的操作。其值可能是:

        大于0:进行信号量的释放操作(V操作),将 sem_op 的值加到对应的信号量值上。

        等于0:进行信号量的等待操作,进程将阻塞直到信号量值变为0。

        小于0:进行信号量的获取操作(P操作),如果信号量的当前值至少是 sem_op 绝对值,那么 sem_op 的绝对值会从信号量值中减去。如果不满足,则根据 sem_flg 的设置可能会阻塞。

sem_flg: 用于控制操作的行为。可能的标志包括:

  IPC_NOWAIT: 如果操作会导致进程阻塞,那么不阻塞而立刻返回。

  SEM_UNDO: 让系统记录这个操作,如果进程在没有释放信号量的情况下终止,系统将自动撤销此前进行的信号量操作。

 

四、理解IPC

我们现在将进程间主要的方式对应的数据结构拿出来:

消息队列:

共享内存:

信号量:

我们可以看到这三个主要的通信方式对应的结构中都有struct ipc_perm这玩意

这是为什么呢?我们来看到下面:

在Linux内核中有个ipc_id_ary的柔性数组,该数组中存储的是一个个ipc_perm结构体的地址:

每当我们创建一个进程间通信的结构体,其内部都会产生一个ipc_perm,操作系统会将该ipc_perm结构体对应的地址存入ipc_id_ary数组中,所以Linux操作系统会将内核中的所有ipc资源统一以数组的方式进行管理

这样子我们就可以拿到特有的key值去找到ipc_id_ary数组中对应的结构体,找到对应下标,那有了对应的的下标后该怎么管理内部资源呢?ipc_perm*的指针怎么访问其他成员呢?

指针强转一下不就好了嘛:((struct XXXid_ds*)ipc_id_arr[n])->other....

不过上面讲述的都是原理,其内核的具体实现方式相当复杂

最后有没有发现,对于上述的管理方式好像多态?

没错,这就是C语言中的多态表现方式!所以面向对象的语言并不是偶然产生的,这是由大量工程经验所导致的必然结果~

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

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

相关文章

2023.1.21 关于 Redis 主从复制详解

目录 引言 单点问题 分布式系统 主从模式 配置 Redis 主从结构 断开主从关系 切换主从关系 补充知识点一 只读 网络延迟 拓扑结构 一主一从 一主多从 树形主从结构 主从复制的基本流程 数据同步 replicationid offset pzync 运行流程 具体流程 补充知识点二…

C. Doremy‘s City Construction(二分图问题)

思路&#xff1a;把集合划分成两部分,一部分中每个数都比另一部分小,这两部分连成一个完全二分图,这种情况是最优的,还需要特判所有数都相等的情况. 代码&#xff1a; void solve(){int n;cin >> n;vector<int>a(n 1);for(int i 1;i < n;i )cin >> a[…

如何使用iPhone或iPad上的二维码共享Wi-Fi密码?这里有详细步骤

你有没有想过在不泄露网络密码的情况下与客人共享你的家庭或工作Wi-Fi?你肯定不是第一个这样想的人,我们很高兴地通知你,多亏了以下这个的变通方法,你现在可以使用iPhone或iPad做到这一点。 通常,如果你想让其他人访问网络,你需要共享你的Wi-Fi密码。苹果通过引入与任何…

python 学习之 re库的基本使用(正则匹配)上

目录 一、基本用法 二、函数介绍 1、match函数 2、search 函数 3、compile 函数 4、findall 和 finditer 函数 5、sub 函数和 subn 函数 6、split 函数 一、基本用法 首先我们需要引入 re 库 代码基本框架使用两行代码实现 测试代码&#xff1a; import reret re.m…

vue 本地中导入 maptalks

1、进入 github 中 maptalks 文件下载页面&#xff08;https://github.com/maptalks/maptalks.js/releases&#xff09; 这里可能会有朋友应为网络问题打不开 github &#xff0c;可以查看作者另一篇关于解决该问题的文章&#x1f449;GitHub 打不开问题解决 2、将下载好的文件…

5V摄像机镜头驱动芯片GC6208,为什么可以替代AN41908,适用于摄像机镜头上

GC6208是一个镜头电机驱动IC摄像机和安全摄像机。该装置集成了一个由PID控制的可变光圈直流电机驱动器和两个通道的扫描隧道显微镜电机驱动器&#xff0c;用于变焦和聚焦控制。AN41908A是一款用于摄像机和安全摄像机的镜头马达驱动IC&#xff0c;具有lris控制功能。电压驱动系统…

.zip 文件和 .tar.gz文件 的区别

tgz和zip两种压缩格式,其实这两个压缩文件里面包含的内容是一样的,只是压缩格式不一样. tar.gz格式的文件比zip文件要小不少。tar.gz压缩格式用于unix的操作系统, 而zip用于windows的操作系统,但在windows系统中WinRar工具同样可以解压缩tar.gz格式的。 扩展&#xff1a; z…

仿真机器人-深度学习CV和激光雷达感知(项目2)day5【作业1与答案1】

文章目录 前言作业1答案1 前言 &#x1f4ab;你好&#xff0c;我是辰chen&#xff0c;本文旨在准备考研复试或就业 &#x1f4ab;本文内容是我为复试准备的第二个项目 &#x1f4ab;欢迎大家的关注&#xff0c;我的博客主要关注于考研408以及AIoT的内容 &#x1f31f; 预置知识…

在Rust中编写自定义Error

前言 之前我们聊过&#xff0c;Result<T, E> 类型可以方便地用于错误传导&#xff0c;Result<T, E>是模板类型&#xff0c;实例化后可以是各种类型&#xff0c;但 Rust 要求传导的 Result 中的 E 是相同类型的&#xff0c;或者能够自动转化为相同类型。比如&#…

【Jetbrains全家桶】PyCharm专业版学生用户申请(学信网)+Toolbox App安装配置教程(修改系统、配置和日志目录)

文章目录 一、Jetbrains学生用户免费使用1. [Jetbrains官网](https://www.jetbrains.com.cn/en-us/)新申请更新资料申请界面 2. [学信网](https://www.chsi.com.cn/xlcx/index.jsp)教育部学籍在线验证报告本人身份核验申请报告 二、安装Toolbox App[Toolbox App](https://www.j…

Qt 拖拽事件示例

一、引子 拖拽这个动作,在桌面应用程序中是非常实用和具有很友好的交互体验的。我们常见的譬如有,将文件拖拽到某个窗口打开,或者拖拽文件到指定位置上传;在绘图软件中,选中某个模板、并拖拽到画布上,画布上变回绘制该模板的图像… 诸如此类,数不胜数。 那么,在Qt中我…

开源项目Git Commit规范与ChangeLog

一&#xff0c;conventional commit(约定式提交) Conventional Commits 是一种用于给提交信息增加人机可读含义的规范。它提供了一组用于创建清晰的提交历史的简单规则。 1.1 作用 自动化生成 CHANGELOG基于提交类型&#xff0c;自动决定语义化的版本变更向项目相关合作开发…

shell脚本—循环语句

文章目录 循环语句循环含义1、for2、whilewhile循环 3、until4、双重循环及跳出循环 循环语句 echo命令&#xff1a;标准输出或提取shell变量的值 标准输出 [rootlocalhost ~]#echo 123456|passwd --stdin zhangsan 更改用户 zhangsan 的密码 。 passwd&#xff1a;所有的身…

SWMM模型INP解析

.INP文件解析 [OPTIONS]&#xff1a;SWMM软件运行前需要设置的参数 [RAINGAGES]雨水节点&#xff0c;核心设置雨水时间序列&#xff0c;可为INP内部数据也可为外部txt数据&#xff0c;TIMESERIES对应【TIMESERIES】模块&#xff0c;TS_1为时间序列名称 [TIMESERIES]&#xff0…

部署幻兽帕鲁联机服务器需要怎样配置的云服务器?

随着互联网技术的快速发展&#xff0c;多人在线游戏逐渐成为人们休闲娱乐的重要方式。作为一款备受欢迎的游戏&#xff0c;幻兽帕鲁以其独特的玩法吸引了大量玩家。为了获得更好的游戏体验&#xff0c;许多玩家选择在云服务器上自行部署幻兽帕鲁联机服务器。本文将详细介绍部署…

设置模式之责任链模式

目录 1.概述 2.结构 3.实现 4.总结 1.概述 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为性设计模式&#xff1b;它为请求创建了一个接收者对象的链&#xff0c;允许你将请求沿着处理者链进行发送。 收到请求后&#xff0c; 每个处理者均…

图像处理python基础

array 读取图片 tensor 模型预测 一般过程&#xff1a;读取数据np->tensor->model->result->np->画图 shape确保图像输入输出尺寸正确 读取图片 将在GPU上运行的tensor类型转变成在CPU上运行的np类型 三类计算机视觉任务的输入&#xff1a; 分类&#xff1…

【软考问题】-- 1 - 知识精讲 - 项目管理理论

一、基本问题 1&#xff1a;项目的特点是什么&#xff1f; 临时性&#xff1a;是指项目有明确的起点和终点&#xff0c;从项目启动到项目收尾。项目目标实现后&#xff0c;项目收尾工作完成即标志着项目结束。独特性&#xff1a;项目是独特的&#xff0c;之前没有做过的&#x…

JS高频面试题(上)

1. 介绍JS有哪些内置对象&#xff1f; 数据封装类对象&#xff1a;Object、Array、Boolean、Number、String 其他对象&#xff1a;Function、Arguments、Math、Date、RegExp、Error ES6新增对象&#xff1a;Symbol&#xff08;标识唯一性的ID&#xff09;、Map、Set、Promise…

Python + Selenium —— 网页元素定位之CSS 选择器!

CSS(Cascading Style Sheets)是一种语言&#xff0c;用来描述HTML和XML文档的样式。 CSS 选择器用来定位 HTML 上的元素&#xff0c;然后对其进行渲染。通过 CSS 选择器可以定位到页面上的任意元素。这些选择器可以被 WebDriver 用作另外的定位策略。 CSS 可以较为灵活的选择控…