linux入门---信号量

news2024/12/23 3:41:40

什么是信号量

信号量的本质是一个计数器,通常用来表示公共资源中资源数量多少,公共资源是指可以被多个进程同时访问的资源,访问没有被保护的公共资源时可能出现数据不一致的问题,比如说一个进程对公共资源执行一些写操作,当写操作完成了一半时另外一个进程就对该公共资源进行了读取,那么这个时候就会出现数据不一致的问题,这里先暂停一下我们来回顾一下这里的逻辑:我们为什么要让不同的进程看到同一份资源呢?因为我们想要实现通信从而来实现进程之间的协同,又因为进程之间具有独立性没有办法让进程之间直接通信,所以我们得让进程看到同一份资源,这是我们提出的解决问题的方法但是这个方法又会引入了新的问题:数据不一致,所以我们得将实现通信的公共资源保护起来,我们把被保护的公共资源称为:临界资源,那么未来我们要干的事情就和如何保护公共资源有关,在保护公共资源的时候就会使用到信号量这个东西。我们程序的大部分资源都是独立的,资源(内存资源,文件资源,网络资源)是要被进程使用的,那资源又是如何被进程使用的呢?一定是该进程里有对应的代码来访问这部分临界资源,我们把访问临界资源的代码称为临界区,访问非临界的资源的代码称为非临界区。看到这里想必大家应该知道了这里的逻辑,我们写的程序会访问公共资源,为了保护公共资源的安全,所以得对这部分资源进行保护,保护得使用信号量(如何使用我们以后再说)保护的方法就是互斥和同步,同步的概念我们后面再详细的解答,互斥的意思就是:我访问的一部分资源或者做某件事的时候你必须得等,同样的道理你在访问某部分资源或者做某件事情的时候我也必须得等,你做完了我或者其他人才能继续做那么我们就把要么做就做完,要么就不做的这两种情况称为:原子性,而信号量的作用就是通过原子性来保护公共资源。

为什么要有信号量

我们可以通过电影院买票的例子了解信号量,电影院的买票机制实际上是对放映厅中的座位进行预定机制,当我们想要某种资源的时候就可以对该资源进行预定,比如说我买了电影票电影院就会帮我对某个位子进行预定,即使我们不去电影院但是那个位置上面不能有其他人,所以电影院得有机制来保证电影票不能多卖和错卖,那么公共资源也是同样的道理,公共资源有时候会作为一个整体来进行使用,有时候也会变为一个一个的资源字部分来进行使用,那么我们人就相当于操作系统中的进程,电影院的每个座位就相当于共享资源的一小部分,人通过购买电影票来对座位进行预定就相当于进程通过申请信号量从而对共享资源进行预定,如果对信号量的申请失败了那么信号量就不允许该进程访问共享资源从而对共享资源进行了保护。信号量的本质是计数器,申请信号量就得对计数器进行减减从而预定了公共资源,释放公共资源之后就得对信号量进行加加,所有的进程在访问公共资源之前,都必须先申请信号量,申请信号量的前提是所有进程必须先得看到同一个信号量,所以这里就可以推出信号量本身就是公共资源,既然是公共资源那么就一定存在数据安全问题,所以信号量也得保证自己的数据安全,所以信号量的++和–操作也必须得是原子的,我们将信号量的增加称为p操作,信号量的减少是称为v操作。如果一个信号量的初始值为1的话我们就称之为二元信号量,也就是说一个资源要么你不能访问,要么就只有你能够访问,所以也可以将其称为互斥信号量。这里大家得注意一点信号量申请成功了并不代表我们接下来就能够访问共享资源,申请信号量成功只能说明共享资源中可能有个资源属于我,这就好比我们购买高铁票的时候可能是先购票成功了,然后过了一会出票的时候才知道自己具体坐着哪个车厢的哪个位置上,所以申请信号量成功就相当于购票成功了,但是具体要访问哪个资源还是不知道,所以这一部分的工作还得交给程序员来完成

信号量有关的函数

首先我们了解一下semget函数:
在这里插入图片描述
这个函数的作用就是用来申请一个能够被所有进程看到的信号量,第一个参数就是key,第二个参数用来表示申请了几个信号量如果你想申请10个信号量就传递10给第二个参数,semflg就是之前的标识位,申请成功了就返回信号量集合的标识符,申请失败了就会返回-1,接下来就是信号量控制函数
在这里插入图片描述
第一个参数表示对信号量的id也就是semget函数的返回值,如果你相对哪个信号量进行操作就传递对应信号量的标识符,因为信号量会存在多个,所以第二个参数表示的意思就是要操作的信号量的下标,如果想对标识符为semid的第二个信号量进行操作,那么这个参数就应该传递为1,cmd就是标识符不同的标识符有不同的功能,比如说想要删除信号量就可以传递信号量IPC_RMID, 如果想要执行其他的操作就可以传递其他的标识符:
在这里插入图片描述
根据前面的讲解我们知道信号量是一个计数器,所以他一定存在对应的加减计数器的操作:
在这里插入图片描述
第一个参数表示对哪个信号量进行操作,第二个参数是一个结构体,这个结构体里面存在三个参数:
在这里插入图片描述
第一个参数表示你相对多个信号量中的哪个信号量进行操作,假设只有一个信号量那么这个参数传递的值就是0,第二个参数表示你要执行的操作,这个参数可以设置的值为1或者-1,如果值为1就是对指定的信号量进行加加,如果该该值为-1就表示对指定的信号量进行减减,第三个选项就直接设置为0就可以了,那么这就是第二个参数的作用,第三个参数表示要对几个信号量进行操作,如果想一次性对10个信号量进行操作那么第三个参数就可以传递10,并且第二个参数就传递一个结构体数组那么这就是信号量有关的操作,这里我们在后面的多线程保护会继续的给大家进行讲解。

IPC资源的组织方式

共享内存有自己的属性所以有对应的结构体来描述共享内存,我们可以通过shmctl来进行查看:
在这里插入图片描述
这里有两个结构体,两个结构体共同描述共享内存的属性,与共享内存相似的还有消息对量他也是一个共享资源,所以也存在对应的结构体来描述这一部分资源,那么这里可以使用msgctl函数来进行查看:
在这里插入图片描述
可以看懂这里也是两个结构体一起描述的该资源的属性,我们刚刚学习了信号量,信号量的本质就是一个计数器也是一个共享资源,所以他也存在对应的结构体来描述他的属性,那么这里就可以使用semctl来进行查看:
在这里插入图片描述
可以看到这里也是两个结构体描述的共享资源,大家仔细的观察一下可以看到描述这三个共享资源的两个结构体中,都有一个名为ipc_perm结构体,并且另外一个结构体中的第一个字段都是ipc_perm结构体对象,所以这就可以看出这就是system V标准的进程间通信,所谓的标准就是大家使用的方式,接口的设计,数据结构的设计都必须符合该标准,那操作系统又是如何管理这些数据呢?比如说我申请了5个共享内存,然后又申请了3个消息队列,最后又申请了4个信号量,那操作系统如何管理这些资源的呢?首先我们可以知道每个共享资源的结构体中的第一个字段都是ipc_perm,并且ipc_perm结构体中存在一个字段来记录key值从而保证数据的唯一性:
在这里插入图片描述
那么操作系统要想管理不同的共享资源就只用创建一个ipc_perm的数组就可以了,比如说下面的图片:
在这里插入图片描述
我们没申请一个共享资源操作系统就会创建对应的结构体,比如说申请一个共享内存一个消息队列一个信号量,那么操作系统就会创建对应的结构体对象,比如说下面的图片
在这里插入图片描述
因为这三个结构体中的第一个元素都是ipc_perm所以我们可以让数组中的元素指向三种结构体中的第一个成员:
在这里插入图片描述
因为结构体中的第一个元素的地址和该结构体的地址是一模一样的,只是地址的类型不一样,所以当我们想要访问对应的属性时就可以通过数组来获取对应的地址,然后将地址的属性进行修改就行,比如说数组中的第一个元素指向的是共享内存的结构体,那么我们就可以通过数组的下表访问到具体的地址:perms[0],然后就直接进行强转便可以访问到结构体中的其他元素:(struct shmid_ds*)perms[0],那么通过这样的方法就可以将不同的结构体资源通过一个数组来进行保存 ,那么这里大家可能还有点疑惑,计算机怎么知道哪个下表的元素存储的是哪个资源的结构体呢?那么这里大家就不用担心我们可以创建一个结构体,结构体中的第一个元素为整形用来表示数据的类型,第二个参数就是一个ipc_perm的指针,用来指向数据结构体中的第一个元素,比如说下面的代码:

struct myIPC
{
	int type;
	struct ipc_perm*;
}

这样我们就从维护一个指向ipc_perm的指针数组变成维护一个myIPC的结构体数组,所以这里大家不用担心,那么看到这里想必大家对这个非常的眼熟,好想和c++中的多态类似,没错这就相当于c语言实现的多态,当年c++实现多态的时候可能思路就来自于此,ipc_perm就相当于c++中的基类,那三个共享资源的描述对象就相当于派生类,我们通过派生类的指针指向派生类的第一个元素就然后通过强制类型转换就可以访问派生类的其他成员和属性,那么这就是IPC资源的组织方式。

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

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

相关文章

Python 数据分析与挖掘(一)

Python 数据分析与挖掘(数据探索) 数据探索 1.1 需要掌握的工具(库) 1.1.1 Nump库 Numpy 提供多维数组对象和各种派生对象(类矩阵),利用应用程序接口可以实现大量且繁琐的数据运算。可以构建…

一文搞懂如何求MOS管的等效阻抗

首先先明确方法论,求等效电阻有多种方法,这里使用加压求流法,即我们要求从MOS的哪端看进去等效阻抗,就在哪个端口加一个电压源,并将原电路所有独立源置零(电压源短路,电流源断路)&am…

【MySQL】MySQL 官方安装包形式

MySQL 官方提供3种包: 1. 源码包 mysql-5.7.42.tar.gz mysql-5.7.42-aarch64.tar.gz http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.34.tar.gz http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.42.tar.gz需要用户根据自己的CPU架构选择对应的…

文心一言 VS 讯飞星火 VS chatgpt (103)-- 算法导论10.1 1题

一、用go语言,仿照图 10-1,画图表示依次执行操作 PUSH(S,4)、PUSH(S,1)、PUSH(S,3)、POP(S)、PUSH(S,8)和 POP(S)每一步的结果,栈 S初始为空,存储于数组 S[1…6]中。 文心一言&…

国庆10.01

TCPselect 代码 服务器 #include<myhead.h> #include<sqlite3.h> #define PORT 6666 //端口号 #define IP "192.168.0.104" //IP地址//键盘事件 int jp(fd_set tempfds,int maxfd) {char buf[128] ""; //用来接收数据char buf1[128] …

RHEL8.0安装+基础命令练习+discuz(lamp)论坛搭建

上课练习环境&#xff1a; RHEL8.0系统镜像下载&#xff1a; 链接1&#xff1a;https://pan.baidu.com/s/1wX2j-aTO1VRcHQYpCDYnEg 提取码&#xff1a;6buv 链接2&#xff1a;https://ws28.cn/f/32i4oq8p5r1 &#xff08;下载完2个文件后只需要解压001&#xff0c;推荐压缩…

树莓派4B串口通信配置方式

目录 1树莓派4B的安装&#xff1a; 1.1安装Serial与使用 1.1.1安装serial 1.1.2打开串口 1.2设置硬件串口为GPIO串口&#xff08;修改串口映射关系&#xff09; 1.2.1修改配置文件 2.1minicom串口 2.1.1安装minicom 这篇博客源于&#xff1a;工创赛。需要让树莓派与STM…

Java集合处理Stream流使用解析

Stream Stream是Java 8引入的一个新的API&#xff0c;用于处理集合数据的流式操作。它提供了一种更简洁、更灵活的方式来处理集合数据&#xff0c;可以实现更高效的数据处理和转换。 使用Stream&#xff0c;可以通过一系列的操作来对集合数据进行筛选、映射、排序、聚合等操作…

SpringBoot终极讲义第一章笔记

01.Spring Boot简介 1.Spring的本质和作用 spring的本质就是一个"容器",它负责创建并管理容器中的对象(组件,也称为Bean),并管理组件之间的依赖关系(何为依赖关系:A组件需要调用B组件方法,称为A依赖于B) 因此学习Spring最常用的两个注解: Component:将被修饰的类…

使用VSCODE 调试ros2具体设置

vscode 调试 ROS2 张得帅&#xff01; 于 2023-09-09 15:39:39 发布 456 收藏 1 文章标签&#xff1a; vscode ros2 版权 1、在下列目录同层级找到.vscode文件夹 . ├── build ├── install ├── log └── src 2、 安装ros插件 3、创建tasks.json文件&#xff0c;添…

真正理解浏览器渲染更新流程

浏览器渲染更新过程 文章目录 浏览器渲染更新过程帧维度解释帧渲染过程一些名词解释Renderer进程GPU进程rendering(渲染) vs painting(绘制)⭐位图纹理Rasterize(光栅化) 1. 浏览器的某一帧开始&#xff1a;vsync2. Input event handlers3. requestAnimationFrame4. 强制重排(可…

Git/GitHub/Idea的搭配使用

目录 1. Git 下载安装1.1. 下载安装1.2. 配置 GitHub 秘钥 2. Idea 配置 Git3. Idea 配置 GitHub3.1. 获取 GitHub Token3.2. Idea 根据 Token 登录 GitHub3.3. Idea 提交代码到远程仓库3.3.1. 配置本地仓库3.3.2. GitHub 创建远程仓库1. 创建单层目录2. 创建多层目录3. 删除目…

【数据结构】二叉树链式结构补充和二叉树的顺序结构及实现

&#x1f407; &#x1f525;博客主页&#xff1a; 云曦 &#x1f4cb;系列专栏&#xff1a;数据结构 &#x1f4a8;吾生也有涯&#xff0c;而知也无涯 &#x1f49b; 感谢大家&#x1f44d;点赞 &#x1f60b;关注&#x1f4dd;评论 文章目录 前言&#x1f4da;一、二叉树链…

机器人过程自动化(RPA)入门 8. 异常处理、调试和日志记录

有时,自动化程序可能无法执行。为了处理此类情况,我们使用异常处理活动。在本章中,我们将从UiPath中可用的各种类型的异常处理方法、您可能遇到的异常以及如何处理它们开始。我们还将学习日志记录。本章涉及的一个重要主题是调试,以检查工作流是否正常工作,并更正任何错误…

Neural Networks for Fingerprint Recognition

Neural Computation ( IF 3.278 ) 摘要&#xff1a; 在采集指纹图像数据库后&#xff0c;设计了一种用于指纹识别的神经网络算法。当给出一对指纹图像时&#xff0c;算法输出两个图像来自同一手指的概率估计值。在一个实验中&#xff0c;神经网络使用几百对图像进行训练&…

Python学习之索引与切片

Python学习之索引与切片 s “0abcdefghijklmnopqrstuvwxyz”&#xff0c;第一个元素‘0’&#xff0c;索引号为0&#xff0c;最后一个元素‘z’&#xff0c;索引号为26 1. s[0]获取索引号为0的元素 2. s[1:3]获取索引号为1的元素&#xff0c;直到但不包括索引号为3的元素。即…

大数据-玩转数据-Flink Sql 窗口

一、说明 时间语义&#xff0c;要配合窗口操作才能发挥作用。最主要的用途&#xff0c;当然就是开窗口然后根据时间段做计算了。Table API和SQL中&#xff0c;主要有两种窗口&#xff1a;分组窗口&#xff08;Group Windows&#xff09;和 含Over字句窗口&#xff08;Over Win…

S32K144 GPIO编程

前面的文章介绍了如何在MDK-Keil下面进行S32K144的开发&#xff0c;下面就使用该工程模板进行GPIO LED的编程试验。 1. 开发环境 S32K144EVB-Q100开发板MDK-Keil Jlink 2. 硬件连接 S32K144EVB-Q100开发板关于LED的原理图如下&#xff1a; 也就是具体连接关系如下&#xf…

【知识点随笔分析 | 第五篇】简单介绍什么是QUIC

前言&#xff1a; 随着互联网的快速发展&#xff0c;传统的基于TCP的协议开始显现出一些局限性。TCP在连接建立和拥塞控制方面存在一定的延迟&#xff0c;这可能导致用户在访问网页、观看视频或玩网络游戏时感受到不必要的等待时间。而QUIC作为一种新兴的传输协议&#xff0c;试…

Java编程技巧:swagger2、knif4j

目录 1、springbootswagger2knif4j2、springbootswagger3knif4j3、springcloudswagger2knif4j 1、springbootswagger2knif4j 2、springbootswagger3knif4j 3、springcloudswagger2knif4j 注意点&#xff1a; Api注解&#xff1a;Controller类上的Api注解需要添加tags属性&a…