同步与互斥(3)--信号量机制

📅 2026/7/19 3:48:15
同步与互斥(3)--信号量机制
操作系统信号量机制前文我们讲完了软件、硬件两大类互斥实现方案但不管是 Peterson 算法还是 TSL、开关中断全都卡在无法满足「让权等待」这一条核心原则进程拿不到锁时会循环忙等死死占用 CPU 空耗算力。 而信号量机制是操作系统标准解法分为整型信号量与记录型信号量两代最终记录型信号量可以完整满足互斥四大准则完美实现进程互斥与同步也是 PV 操作经典题型的底层根基。一、信号量基础概念铺垫1. 信号量是什么信号量本质就是用来统计系统可用资源数量的变量数值 当前还剩下多少份可用资源系统严格规定信号量仅能执行三种操作初始化、P 操作申请资源、V 操作释放资源不允许程序随意直接修改变量数值从根源避免并发错乱。2. PV 原语Wait / SignalP 操作 wait(S)向系统申请占用一份资源对应进入区上锁 V 操作 signal(S)使用完毕归还释放一份资源对应退出区解锁。 P、V 属于原语执行过程关中断、一气呵成不可被打断杜绝多进程并发修改导致逻辑出错。词源小知识P 来自荷兰语proberen尝试、申请V 来自verhogen增加、释放。二、第一代整型信号量1. 结构定义只用一个单独整型变量S.value代表剩余资源总数仅依靠循环判断完成 P/V// P操作 申请资源 while(S.value 0); // 资源不足就一直循环轮询 S.value S.value - 1; // V操作 释放资源 S.value S.value 1;2. 举例公寓里有 1 台公用洗衣机初始化 S1。 租客想洗衣服时执行 P 操作如果洗衣机有人用S≤0就站在洗衣机门口不停反复查看、原地打转直到别人用完 S0立刻占用洗衣机。 用完执行 V把资源数 1 归还。3. 缺陷完全不满足「让权等待」原则。 资源被占用时进程不会放弃 CPU、不会进入阻塞休眠而是无限 while 循环轮询查询状态也就是忙等CPU 大量算力浪费在无效循环上系统资源利用率极低。三、第二代记录型信号量为了解决整型信号量忙等问题给信号量新增阻塞等待队列拿不到资源的进程直接休眠阻塞、让出 CPU完美补齐四大互斥原则最后一块短板。1. 结构体完整定义typedef struct{ int value; // 剩余可用资源数量 struct process *L; // 阻塞等待该资源的进程队列 } semaphore;value资源计数器正数 空闲资源负数绝对值 当前正在排队等待的进程个数L队列存放所有因缺资源而被挂起阻塞的进程。2. P 操作Wait 申请资源void wait(semaphore S){ S.value --; // 先主动扣减一份资源额度 if(S.value 0){ // 扣完后资源不够需要阻塞 block(S.L); // 进程自身进入阻塞态插入等待队列让出CPU } }执行步骤拆解先把剩余资源数 - 1代表我要占用一份如果减完之后value0说明原本没有空闲资源当前进程必须阻塞休眠挂进信号量的等待队列主动放弃处理机不再占用 CPU 轮询。3. V 操作Signal 释放资源void signal(semaphore S){ S.value ; // 先归还一份资源计数器1 if(S.value 0){ // 还有进程在队列里排队等待 wakeup(S.L); // 从等待队列队首唤醒一个进程转为就绪态 } }执行步骤拆解使用完毕资源计数器 1归还占用的资源如果value≤0代表还有进程卡在队列里等待资源操作系统唤醒队首一个阻塞进程让它进入就绪队列等待调度上 CPU。4. 举例依旧是公寓 1 台洗衣机初始化S.value1等待队列为空。租客 A 执行 Pvalue变为 0没有小于 0直接使用洗衣机租客 B 紧接着执行 Pvalue变成 - 1触发blockB 不再站门口死等回房间睡觉阻塞排入等待队列A 洗完执行 Vvalue变回 0此时value≤0系统叫醒队列里的 BB 从阻塞变就绪后续调度使用洗衣机。优势拿不到资源的进程直接休眠彻底告别忙等CPU 可以调度其他无关进程执行完全符合让权等待 同时天然满足空闲让进、忙则等待、有限等待四、关键数值规律初始化Sn代表系统一共有n 份同类临界资源P 一定先value--V 一定先value顺序绝对不能颠倒S.value 0正数 当前还有多少空闲资源S.value 0负数的绝对值 此刻正在等待队列里排队阻塞的进程数量V 操作只有value之后依旧≤0才需要唤醒等待队列里的进程。五、信号量两大核心用途1. 实现进程互斥互斥场景同一资源同一时间只允许 1 个进程访问信号量初值固定设为 1二元信号量 / 互斥锁。 模板写法semaphore mutex 1; // 进程进入临界区前 P(mutex); 临界区代码; // 退出临界区后 V(mutex);2. 实现进程同步同步场景约束多个进程固定先后执行顺序信号量初值一般设为 0。 比如必须 A 进程先执行完B 才能运行初始化S0A 进程末尾写V(S)B 进程开头写P(S)B 会一直阻塞直到 A 执行 V 释放信号量B 才可以继续往下走强制绑定执行先后顺序。六、两代信号量核心对比类型数据结构拿不到资源时行为是否忙等是否满足四大互斥原则整型信号量仅单个 int 变量while 循环轮询是缺少让权等待不完整记录型信号量资源计数 阻塞队列进程阻塞休眠、让出 CPU否四条原则全部满足标准方案七、总结信号量本质是资源计数器P 申请减一V 释放加一PV 属于不可中断原语整型信号量存在忙等缺陷记录型信号量新增等待队列阻塞进程彻底解决 CPU 空转问题P 先减后判断阻塞V 先加后判断唤醒牢记执行顺序是做题核心初值为 1 用于互斥初值为 0 多用于同步记录型信号量是操作系统解决进程同步互斥的通用底层机制。