资讯动态

Linux进程间通信——信号量

发布时间:2026/8/14 4:05:26 来源:尧图企业网站定制
一什么是信号量信号量Semaphore 是操作系统中用于实现进程 / 线程同步与互斥的核心机制本质是一个具有原子操作的整数计数器用来记录可用公共资源的数量。核心目标协调多个进程对共享资源的访问避免数据不一致和死锁问题。原子性P/V 操作不可被中断保证计数器修改的安全要么都不执行要么执行不会被中断。1.1核心操作P 操作与 V 操作信号量的行为由两个原子操作定义1P 操作wait / 申请资源作用申请一个资源如果资源不足进程就会阻塞等待。类比停车场入口取卡车位 - 1车位满了就排队等候。2V 操作signal / 释放资源作用释放一个资源如果有进程在等待就唤醒一个继续执行。类比停车场出口交卡车位 1若有车在等就放一辆进来。1.2信号量的分类1.二元信号量互斥锁取值只能是 0 或 1初始值1表示资源可用作用实现互斥保证同一时间只有一个进程进入临界区。场景保护临界资源如共享变量、文件读写避免并发修改。2.计数信号量通用信号量取值0 ~ NN 为资源总数初始值N表示有 N 个可用资源作用控制最多 N 个进程同时访问资源。场景连接池、缓冲区、线程池等有限资源的管理。1.3相关介绍1. 公共资源 vs 临界资源公共资源可被多个进程同时访问的资源如内存、文件、网络。临界资源需要被保护的公共资源同一时间只能被一个进程访问否则会数据不一致。2. 临界区 vs 非临界区临界区进程中访问临界资源的那段代码必须互斥执行。非临界区进程中不访问临界资源的代码可以并发执行。3.互斥 vs 同步互斥保证临界区同一时间只被一个进程执行解决 “竞争问题”。同步控制进程执行顺序如 A 完成后 B 才能开始解决 “时序问题”。信号量可以同时实现这两种需求。二接口函数1. semget ()创建 / 获取信号量集作用创建新的信号量集或获取已存在的信号量集的标识符semid。成功返回非负整数semid失败返回-1int semget(key_t key,int nsems,int semflg);参数1key_t key信号量集的 “唯一身份证”作用系统通过 key 区分不同的信号量集保证进程间能访问到同一个信号量集。常见取值方式1手动直接赋值自定义固定值key_t key0x66;//直接赋值2通过 ftok() 生成唯一 key// ftok(路径, 项目标识)基于文件inode和标识生成唯一key // . 代表当前工作目录运行程序时的目录S 为项目标识 key_t key ftok(., S); if (key -1) { perror(ftok失败); // 打印具体错误原因如权限不足、目录不存在 exit(1); // 用标准退出码比直接exit(1)更规范 }3IPC_PRIVATE私有信号量key_t key IPC_PRIVATE; // 仅当前进程和子进程可见跨进程无效参数2int nsems信号量集的 “容量”作用指定创建的信号量集中包含多少个独立的信号量。创建新信号量集必须指定 nsems ≥ 1如 nsems3 表示集合里有 3 个信号量获取已存在的信号量集nsems 可以填 0。参数3int semflg创建 / 获取的 “规则”权限 标志作用组合「权限掩码」和「创建标志」控制信号量集的创建 / 获取行为。// 普通创建/获取有则取无则创权限0644 int semflg IPC_CREAT | 0644; // 强制创建全新的存在则报错测试用权限0666 int semflg IPC_CREAT | IPC_EXCL | 0666;// 2. 创建/获取信号量集包含1个信号量权限0644 int semid semget(key, 1, IPC_CREAT | 0644); if (semid -1) { perror(semget failed); exit(1); }2.semctl ()控制信号量作用对信号量集进行初始化、删除、获取状态等控制操作。int semctl(int semid, int semnum, int cmd, .../* union semun arg */);关键参数semid信号量集标识符semnum要操作的信号量编号从 0 开始cmd操作命令核心SETVAL设置信号量初始值GETVAL获取信号量当前值IPC_RMID删除整个信号量集4.可选参数 arg联合体用于传递 / 接收数据// 必须自己定义这个联合体 union semun { int val; // 用于 SETVAL设置单个信号量的值 struct semid_ds *buf; // 用于 IPC_STAT/IPC_SET获取/设置属性 unsigned short *array; // 用于 GETALL/SETALL批量操作 };3.semop ()执行 P/V 操作作用对信号量集里的指定信号量执行原子操作P 申请 / V 释放。int semop(int semid, struct sembuf *sops, unsigned nsops);参数1int semid定位要操作的信号量集来源由 semget() 函数返回创建 / 获取信号量集时得到。参数2struct sembuf *sops定义具体要执行的操作P/Vstruct sembuf { short sem_num; // 要操作的信号量编号从0开始 short sem_op; // 操作类型-1P操作1V操作 short sem_flg; // 操作标志0阻塞IPC_NOWAIT非阻塞SEM_UNDO自动撤销 };成员取值含义sem_num0、1、2...信号量集里的第 N 个信号量比如创建时 nsems3就有 0/1/2 三个编号sem_op-1P 操作申请资源信号量值 - 1若值 0 则阻塞等待1V 操作释放资源信号量值 1若有等待进程则唤醒一个0等待直到信号量值变为 0极少用sem_flg0默认资源不足时阻塞直到能执行操作IPC_NOWAIT非阻塞操作无法完成时直接返回 - 1不等待SEM_UNDO安全兜底进程异常退出时系统自动撤销该进程对信号量的修改避免死锁常用示例// 示例1P操作阻塞申请第0个信号量加SEM_UNDO更安全 struct sembuf p_op {0, -1, SEM_UNDO}; // 示例2V操作释放第0个信号量 struct sembuf v_op {0, 1, SEM_UNDO}; // 示例3非阻塞P操作拿不到资源直接返回 struct sembuf p_op_nowait {0, -1, IPC_NOWAIT | SEM_UNDO};参数3unsigned nsops要执行的操作数量作用告诉系统 sops 数组里有几个操作指令通常是 1即单次 P/V。取值1执行 1 个操作1批量执行多个操作原子性要么全执行要么全不执行。三思考1. 信号量和共享内存为什么要搭配使用搭配原因共享内存是最快的 IPC 机制但无内置同步机制多个进程同时读写会导致数据错乱信号量负责同步互斥保护共享内存的临界区。2.信号量的 P 操作和 V 操作的具体逻辑是什么P/V 操作是信号量的核心原子操作逻辑如下P 操作申请资源1.将信号量值 S S - 12.若 S 0进程阻塞进入等待队列3.若 S ≥ 0进程继续执行成功申请到资源。V 操作释放资源1.将信号量值 S S 12.若 S ≤ 0唤醒等待队列中的一个进程3.若 S 0无等待进程直接完成操作。生活类比P 操作 停车场取卡车位 - 1V 操作 停车场交卡车位 1。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价