【Linux】进程间通信(3)system V信号量

目录

[一 system V信号量](#一 system V信号量)

[1 并发编程 补充概念](#1 并发编程 补充概念)

[2 信号量是什么](#2 信号量是什么)

[3 为什么要有信号量](#3 为什么要有信号量)

[4 怎么办?](#4 怎么办?)

[二 内核时如何管理IPC资源的](#二 内核时如何管理IPC资源的)

​编辑


一 system V信号量

共享内存本质是没有任何保护机制的,所以我们引入一种新的计数--->system V 信号量(用来保护共享内存)

1 并发编程 补充概念

当不同进程看到同一份共享资源时,如果不做任何保护,就会出现并发访问错误(比如数据混乱、结果不一致)---->解决问题提出新方案:信号量和锁

多个执行流(进程)能够看到的同一份公共资源:共享资源
被保护起来的共享资源叫做临界资源(管道就是典型的临界资源)

保护的方式常见:互斥与同步

任何时刻,只允许一个执行流访问资源,叫做互斥
多个执行流访问临界资源时,具有一定的顺序性,叫做同步

系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源

在进程中涉及到互斥资源的程序段叫临界区
你写的代码 = 访问临界资源的代码(临界区) + 不访问临界资源的代码(非临界区)

所谓对共享资源进行保护,本质是对访问共享资源的代码进行保护

临界资源的本质
互斥 + 同步 + 共享资源 = 临界资源。

也就是说,共享资源只有在需要被互斥 / 同步访问时,才会成为临界资源
临界区的意义

程序员通过代码访问共享资源,因此:

你的代码 = 临界区(访问共享资源) + 非临界区(不访问共享资源)。

保护共享资源的关键,就是保护临界区的执行过程

举例

父子进程同时调用 printf 输出内容到 stdout:

stdout 是共享资源,父子进程的 printf 代码段属于临界区。如果没有互斥保护,输出内容会出现混乱、交错,导致结果错误。

有的代码会访问共同资源-->在临界区访问--->临界区被保护起来,访问公共资源的代码

有的代码不会访问公共资源--->在非临界区

保护,就是再进入临界区之前加锁

2 信号量是什么

信号量和信号完全没有关系,有些教材里面也把信号量叫做信号灯

信号量是用来实现同步和互斥的一种技术。

应用场景:公共资源:整体访问(ATM机器)或局部使用(电影院座位)

信号量本质:是一个计数器,用来衡量临界资源,资源数量的计数器

理解:电影院有很多座位,是被所有人共享的,但是很少有人因为座位争执,是因为保证了资源可控,每个人都有份;当我们想看电影的时候,要先申请资源,也就是座位,那这个座位真正属于的时候是什么时候?当你买完票并坐在你的座位上的时候,就开始访问资源。注意:当你买到票时,你就必有座位;即使你没有去,别人也不能占你的座位

买票的本质:对共享资源的一种预定机制

总票数是有限制的,是一个计数器;电影院就相当于内存块

每一个进程进入公共资源或临界区,必须先买票-->申请信号量:本质是对;临界资源进行预定

信号量计数器,做减减操作,叫做p操作,计数器减到0,就不会访问临界区

信号量计数器,做加加操作(离开电影院),叫做v操作

信号量的本质作用:对临界资源的一种预定资源

代码角度:

cs 复制代码
// 信号量计数器
int count = 40;

// P操作:申请信号量
void P() {
    if (count > 0) {
        count--;
    } else {
        // 当前进程阻塞等待
    }
}

// V操作:释放信号量
void V() {
    count++;
}

信号量就是一段代码和属性的集合

细节:

  1. 跨进程共享信号量属于 IPC(进程间通信)资源,目的是让不同进程能够访问同一个信号量,从而实现跨进程的同步与互斥。

  2. 自身安全(原子性) 信号量本身也是共享资源,因此 P、V 操作必须设计为原子操作,确保操作过程不会被打断,避免数据竞争导致信号量状态出错。

  3. 统一遵守的代码规范所有进程访问共享资源(如共享内存)前,都必须先执行 P 操作申请信号量,不允许任何进程绕过信号量直接访问资源,否则保护机制会失效。

  4. 保护逻辑的本质 信号量的保护逻辑,是通过保护访问共享资源的临界区代码,间接实现对临界资源的保护。

  5. 资源分配由程序员维护信号量只负责控制访问权限,不负责划分共享资源的使用范围;进程该访问共享资源的哪一部分,需要由程序员自行设计和管理。

原子的:要么做完,要么不做。绝不能被打断。

为什么重要:信号量(P/V 操作)如果不是原子的,多个进程同时修改计数器,会导致计数错乱,从而让共享资源的保护彻底失败。

如果电影院里只有一个资源,那它就是互斥的,因为只有一份资源,本质也是信号量

3 为什么要有信号量

因为有问题,会发生并发访问;信号量就是为了访问共享资源产生的并发读写问题

4 怎么办?

我们要用到信号量集--->是一个数组 int countern,可管理多种不同资源

,semget 是 System V 信号量 的核心系统调用,用来创建或获取一个信号量集(semaphore set)的标识符

bash 复制代码
NAME
       semget - get a System V semaphore set identifier

LIBRARY
       Standard C library (libc, -lc)

SYNOPSIS
       #include <sys/sem.h>

       int semget(key_t key, int nsems, int semflg);

参数解释:

参数名 作用
key_t key 信号量集的唯一标识,由 ftok() 生成,用来让不同进程找到同一个信号量集
int nsems 信号量集中包含的信号量个数(创建时指定,获取时也必须和创建时一致)
int semflg 创建 / 获取标志位,和 shmget 用法几乎一致: • IPC_CREAT:不存在则创建,存在则获取 • `IPC_CREAT IPC_EXCL:不存在则创建,存在则报错(确保新建)<br>• 额外加上权限(如 0666`)

注意:开辟空间和初始化的工作是分开的

int semstl:控制信号量

cpp 复制代码
int semctl(int semid, int semnum, int cmd, ...);

union semun:对信号量进行初始化

struct semid_ds:获取信号量集合


二 内核时如何管理IPC资源的

操作系统是统一管理所有的IPC资源的!

IPC资源包括有:共享内存,消息队列,信号量 ;对应的结构体中都有 struct ipc_perm(其中最重要的元素是key)

柔性数组:

cpp 复制代码
struct data {
    int size;
    char buffer[0]; // 柔性数组/零长度数组
};

buffer不占用结构体本身的空间,仅作为一个占位符,指向结构体末尾之后的内存区域

C语言结论:结构体变量的地址,和结构体第一个成员的地址,在数字层面上是相等的

struct ipc_idary 是 Linux 内核 中专门用于批量获取 IPC(进程间通信)对象标识符的内核数据结构

struct ipc_idary里包含一个指针数组,表面上数组的每个元素,都是struct ipc_perm;但实际上,由上面的C语言结论得知,我们知道每个元素实际上是共享内存,消息队列,信号量的结构体--->也就是子类结构体

我们观察发现,共享内存,消息队列,信号量的结构体开头都包含struct kern_ipc_perm

Linux 内核利用 C 语言结构体嵌入特性,将公共权限结构体 kern_ipc_perm 作为所有 IPC 对象结构体的首个成员,以此实现统一管理、权限复用和类型安全转换,模拟面向对象的公共基类继承效果

那么struct ipc_idary不就是基类结构体

这个指针数组,是由父类结构体,指向子类对象

这不就是继承(基类结构体放在子类结构体的开头处)和多态嘛!

返回的时候,xxxid也是一个数组下标、假设已知的指针数组的下标为p,那么强转成对应的结构体类型 (struct serm_array*)p-> 就能访问该结构体的内容

但是怎么找到struct ipc_ids这个入口?你怎么知道指向的内容是什么?
在内核中存在三个静态全局变量:msg_ids,sem_ids,shm_ids,有三张表,分别管理自己的IPC资源

内核定义了三个全局变量作为系统 IPC 资源的总入口。

msg_ids:管理消息队列的全局 descriptor。

sem_ids:管理信号量集的全局 descriptor。

shm_ids:管理共享内存的全局 descriptor。

作用:它们是系统启动时初始化的 "总指挥部",告诉内核去哪里找这三类资源的 ID 数组

相关推荐
大树883 小时前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 小时前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质4 小时前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush44 小时前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5204 小时前
Linux 11 动态监控指令top
linux
小宇宙Zz4 小时前
Maven依赖冲突
java·服务器·maven
Inhand陈工5 小时前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智5 小时前
ARP代理--工作原理
运维·网络·arp·arp代理
不会C语言的男孩5 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
shushangyun_5 小时前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化