信号量:互斥、同步、死锁(伪代码解释说明)

发布时间:2026/9/7 20:51:21
信号量:互斥、同步、死锁(伪代码解释说明) 一、信号量基础机制信号量由计数器、等待队列、原子P/V操作组成。P/V 为原子操作执行过程不可被线程调度打断。P、V 标准底层逻辑// P申请资源资源不足则阻塞 P(S){ S--; if(S 0) 线程阻塞进入等待队列; } // V释放资源唤醒阻塞线程 V(S){ S; if(S ≤ 0) 唤醒队列中一个等待线程; }二、信号量实现互斥1. 核心功能保证临界资源同一时刻仅被一个线程访问解决多线程资源竞争问题。2. 核心特征信号量初值 1P、V 在同一线程成对出现所有线程执行逻辑完全一致3. 完整规范伪代码sem mutex 1; Thread(){ P(mutex); // 加锁 访问临界资源; // 临界区 V(mutex); // 解锁 }4. 标准执行流程线程A执行 P计数器变为 0成功进入临界区。线程B并发执行 P计数器变为 -1线程阻塞。线程A执行完临界区执行 V计数器归 0唤醒线程B。线程B获得调度进入临界区执行。5. 适用场景全局变量读写、共享缓冲区、独占外设、多线程日志输出。三、信号量实现同步1. 核心功能约束线程执行顺序让存在依赖的线程按序执行解决任务乱序、资源超限问题。2. 核心特征信号量初值 0 或 NP、V 分布在不同线程线程间存在明确前后依赖关系模型一事件同步初值0任务顺序依赖sem finish 0; // 前置线程完成任务、发送信号 Pre_Thread(){ 执行前置任务; V(finish); } // 后置线程等待信号、再执行 Post_Thread(){ P(finish); 执行后置任务; }执行流程后置线程先执行 P计数器为 -1线程阻塞。前置线程执行完毕调用 V计数器归 0。唤醒后置线程继续执行后续逻辑。模型二资源同步初值N生产者消费者sem empty 5; // 空闲缓冲区数量 sem full 0; // 已填充数据数量 Producer(){ P(empty); 写入缓冲区; V(full); } Consumer(){ P(full); 读取缓冲区; V(empty); }执行流程生产者通过 P(empty) 申请空位无空位则阻塞生产后 V(full) 通知消费者。消费者通过 P(full) 等待数据无数据则阻塞消费后 V(empty) 释放空位。四、同步 互斥 联合模型同步管执行顺序互斥管资源安全sem empty 5; sem full 0; sem mutex 1; // 生产者完整代码 Producer(){ P(empty); // 1. 先同步 P(mutex); // 2. 后互斥 写入共享缓冲区; V(mutex); V(full); } // 消费者完整代码 Consumer(){ P(full); // 1. 先同步 P(mutex); // 2. 后互斥 读取共享缓冲区; V(mutex); V(empty); }核心铁律先P同步、后P互斥顺序颠倒直接死锁五、死锁1. 死锁定义多个线程互相持有对方需要的独占资源相互等待、无线程释放资源导致所有线程永久阻塞、无法推进。2. 标准死锁伪代码// 两个互斥资源 sem lock1 1; sem lock2 1; // 线程1先拿lock1再等lock2 Thread1(){ P(lock1); P(lock2); // 临界区同时操作两个资源 V(lock2); V(lock1); } // 线程2先拿lock2再等lock1 Thread2(){ P(lock2); P(lock1); // 临界区同时操作两个资源 V(lock1); V(lock2); }3. 标准死锁触发流程线程1成功获取 lock1线程2成功获取 lock2。线程1继续申请 lock2资源已被占用线程1阻塞。线程2继续申请 lock1资源已被占用线程2阻塞。两线程均持有自身资源、等待对方资源无线程执行 V 释放资源形成永久循环等待 → 死锁。4. 死锁四大必要条件必须同时满足互斥资源独占不可共享占有且等待持有资源的同时申请新资源不可剥夺资源只能主动释放不能被抢占循环等待线程资源依赖形成闭环5. 最优解决方法统一资源申请顺序所有线程统一先申请 lock1、再申请 lock2破坏循环等待条件。六、同步与互斥 最终对比表维度互斥同步初始值固定 10 / 自定义NP/V 位置同一线程成对出现跨线程配合使用核心作用资源独占、防止竞争冲突约束顺序、控制资源数量代码逻辑所有线程逻辑一致上下游线程逻辑不同七、终极总结互斥初值1同线程P/V解决资源争抢同步初值0/N跨线程P/V解决执行乱序死锁多线程循环持有资源、相互等待全员阻塞