news 2026/5/4 6:33:29

手撕 Linux 信号量:从古老的 PV 原语到现代内核

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手撕 Linux 信号量:从古老的 PV 原语到现代内核

一.信号量的基本概念

我们要想理解什么是信号量,就要先了解什么是对资源的整体使用和对资源的局部使用,我们来看:

在前面的章节中我们讲过ATM机的例子,现在我们在拿它来举例,ATM机这种小房间就是一个很好的对资源整体使用的例子,这个房间中一次只能进去一个人,别人要想进去就只能等里面的人出来,这个小房间的资源就只供一个人去使用。

而电影院想必我们每个人都去过,电影院就是一个很好的对资源进行局部使用的例子,在这间房间中,不只有我们自己可以看电影,座位上的每个人都可以观看电影,而我们通过座位就将电影院的这整个资源给划分为了一个个的局部资源。

通过上面的例子,我们对于资源的整体使用和局部使用有了一个的简单理解,我们今天的重点不在于对资源的整体使用,而在于对资源的局部使用。

我们来思考一个问题:我们在看电影之前或者说我们要看电影,我们首先要干什么?答案很明显,我们要买票我们买票是为了什么呢?为了证明这个座位资源是我的,那么:对于这个座位资源,我们是买了票之后,这个座位就是我的,还是我坐到座位上这个资源才是我的呢?答案是我们买了票,这个座位就是我的,不管我今天去不去,这个座位就只能我坐,所以我们买票的本质就是:对资源的预定机制!!!

有了对上面的认识后,我们在来思考一个问题:作为一家电影院的老板,你最担心的是什么呢?

答案其实就两点:

1.多卖票。明明电影院就100个座位,却卖了110张票,那么就必然就有人没有座位,自然就会起冲突,没一个电影院的老板想看到这种现象。2.卖重复的票。一个座位按理说只能卖一张电影票,但却卖了10张,那么导致的后果就是这10个人争夺这一个座位,出现这种情况可谓是灾难性的。

对于这第二种卖重复的票我们暂且先不提,我们先着重说这第一种情况:我们在买票的时候,都会有一个售票系统,那么售票系统是怎么知道票是否卖完了呢?

答案就是这个售票系统的底层实现中,一定会有一个计数器,这个计数器记录了电影院有多少个座位,有多少个座位就卖多少张票,也就是这个计数器描述了电影院座位资源的多少。

而我们今天要讲的信号量,本质就是一个计数器,一个描述临界资源多少的计数器!!!

我们现在将视角转移到计算机中,我们可以通过信号量这个计数器,就可以保证:

1.资源不会出现多申请的情况,也就是上面的多卖票的情况。2.所有的进程或线程未来想进入临界区,去访问临界资源,都要先申请信号量,就如同上面我们要先买票一样。

既然是一个计数器,那么不可避免的我们就要对其进++和--的操作,--操作就表示我们申请了一份资源,++操作表示我们归还了一份资源。

对于信号量的++和--操作,我们对其有更优雅的称呼:--操作我们称之为P操作,++操作我们称之为V操作

讲到这里可能有人就问了:每个线程都要申请信号量的话,那么前提就是所有的线程都要看到信号量,也就是信号量本身就是共享资源,它保护了临界资源的安全,该怎么保护自己的安全呢?

答案就是我们改变信号量的方式就是通过PV操作,那换句话说,我们保证了PV操作的安全,也就保证了信号量的安全,那么该如何保证PV操作的安全呢?我们知道PV操作也就是--和++的操作,这种操作是可以被打断的,所以我们的做法就是让PV操作具有原子性,让--和++的过程不可被打断,这样就保证了PV操作的安全,也就保证了信号量的安全。

二.快速认识一下信号量接口

下面我们就来看看信号量的接口都有哪些:

那么第一个函数就是:sem_init,这个函数我们看名字就知道就是对信号量进行初始化。

而它的返回值很简单,成功就返回0,失败了就返回-1并且设置错误码。

下面我们来介绍它的三个参数:

1.sem_t *sem这个参数的作用很简单,我们既然想对信号量进行初始化,那得指明你要对那个信号量进行初始化吧,所以该参数的作用就是指明要初始化的对象。2.int pshared这个参数就有意思了,这个参数是一个int类型的参数,根据POSIX标准,这个函数的类型分为0和非0这两类。当该参数为0时,表示该信号量是进程内私有的,它只能被同一个进程内的不同线程使用,简单理解就是当前的信号量是在线程之间使用的。当该参数为非0时,表示该信号量是进程间共享的,也就是在进程间去使用。3.unsigned int value既然信号量是一个计数器,那我们总要给它设置一个起始值吧,所以该参数就是来设置信号量的初始值。

既然对一个信号量进行了初始化,那么我们不用的时候就要将其销毁,所以要用到的函数就是:sem_destroy

它的返回值和上面的sem_init一样,都是成功了返回0,失败了就返回-1,并设置错误码。

那么下面就是要对信号量进行操作的函数了,第一个就是:sem_wait

我们只看这个函数并不知道它是什么意思,而第二张图中的decrements就揭示了它的作用,没错,就是:P操作,也就是对信号量进行--操作。

那么与之相对应的就是:sem_post,上面的sem_wait函数是P操作,那么该函数就是就是:V操作,也就是对信号量进行++操作

三.基于环形队列的生产者消费者模型

下面我们就要通过信号量来实现一个基于环形队列的生产者消费者模型,那么首先我们先来简单介绍一下环形队列。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/4 6:32:22

物联网Mesh网络API设计:轻量级抽象层实现跨平台设备通信

1. 项目概述:一个面向物联网的轻量级Mesh网络API最近在折腾一个智能家居项目,想把家里的几个传感器节点和控制器连成一个稳定、低功耗的本地网络。市面上的方案要么太重(比如直接上MQTT云),要么太底层(比如…

作者头像 李华
网站建设 2026/5/4 6:32:19

社交AI个性化推理引擎设计与优化实践

1. 项目背景与核心挑战社交推理类AI应用(如虚拟聊天伴侣、游戏NPC等)面临一个根本性矛盾:既要保持对话的逻辑一致性,又要适配不同用户的个性化偏好。传统方法通常采用固定规则或统一模型,导致交互体验生硬。我们团队在…

作者头像 李华
网站建设 2026/5/4 6:26:44

密集图像描述技术:规则系统与强化学习的融合创新

1. 项目背景与核心价值在计算机视觉领域,密集图像描述(Dense Image Captioning)一直是个极具挑战性的任务。不同于传统的图像标注只需生成单一描述,密集描述要求模型能够识别图像中的多个显著区域,并为每个区域生成精准…

作者头像 李华
网站建设 2026/5/4 6:25:06

PD-1/PD-L1免疫治疗机制与临床应用解析

1. PD-L1阻断机制与免疫治疗原理肿瘤细胞通过表达PD-L1配体与T细胞表面的PD-1受体结合,形成免疫检查点抑制信号。这种"分子伪装"使肿瘤逃避免疫系统监视,具体表现为:PD-L1/PD-1结合后激活SHP2磷酸酶阻断TCR信号通路中的ZAP70磷酸化…

作者头像 李华
网站建设 2026/5/4 6:14:27

告别手动操作:用Python脚本自动化备份本地文件到华为云OBS

用Python打造智能文件备份系统:华为云OBS自动化实践指南 每次手动备份重要文件时,你是否担心遗漏关键数据?当硬盘突然崩溃,那些未备份的项目文档和客户资料该如何找回?本文将带你构建一个基于Python的智能备份系统&…

作者头像 李华