【计算机基础】-12-为什么不能用全局变量替代mutex,进行临界资源的保护?请举例说明,哪种情况勉强可以?

📅 发布时间:2026/7/10 2:10:38 👁️ 浏览次数:
【计算机基础】-12-为什么不能用全局变量替代mutex,进行临界资源的保护?请举例说明,哪种情况勉强可以?
这是一个非常经典且重要的并发编程问题。通常情况下不能用普通全局变量替代 mutex 来保护临界资源但在极其受限的特定场景下如单核、无中断、单线程调度器等可能“勉强可行”。下面我们通过原理分析、反例说明和例外情况来全面解答。一、为什么通常不能用全局变量替代 mutex核心问题缺乏原子性 缺乏内存屏障 无法阻塞等待❌ 错误示例用全局变量模拟锁volatile int my_lock 0; // 全局“锁” void critical_section() { while (my_lock 1); // 忙等待 //此处可能被线程切换, 导致多个线程同时获得my_lock 0 my_lock 1; // 获取“锁” // 访问临界资源如全局缓冲区 shared_data; my_lock 0; // 释放“锁” } 问题1非原子操作导致竞态条件Race Conditionmy_lock 1和my_lock 1是两个独立操作。在多核或多线程环境下可能发生时间线程A线程Bt1读 my_lock → 0t2读 my_lock → 0t3写 my_lock 1t4写 my_lock 1→两个线程同时进入临界区锁完全失效。✅ 正确做法使用原子交换如 test-and-set、compare-and-swap而普通赋值不是原子的。 问题2编译器/处理器重排序破坏逻辑即使加了volatile也只能防止编译器优化不能阻止 CPU 乱序执行也不能保证内存可见性尤其在多核系统中。例如my_lock 1; shared_data 42; // 可能被 CPU 重排到 my_lock1 之前其他 CPU 可能看到my_lock1但shared_data还是旧值。✅ mutex 内部使用内存屏障memory barrier 确保操作顺序和可见性。 问题3忙等待浪费 CPU且无法睡眠全局变量方案只能“忙等待”busy-wait持续占用 CPU。真正的 mutex 在锁被占用时会让线程睡眠由操作系统调度其他任务高效节能。 问题4不可重入、无所有权如果同一个线程两次获取“锁”会死锁因为my_lock已为 1。真正的 mutex 支持递归锁如 POSIX 的PTHREAD_MUTEX_RECURSIVE。mutex 有所有权概念只有加锁的线程才能解锁。二、哪种情况“勉强可以”⚠️ 极其有限只有在满足所有以下条件时用全局变量才“勉强可用”但仍不推荐条件说明✅单核 CPU无真正并行只有并发靠中断或任务切换✅ 禁用中断在临界区关闭中断防止上下文切换✅无操作系统 or 协作式调度任务不会被抢占只在 yield 时切换✅仅用于简单标志位不涉及复杂状态机✅ 示例裸机单片机如 LPC1768中的中断 vs 主循环volatile int flag 0; // 中断服务程序ISR void UART_IRQHandler(void) { if (uart_rx_complete()) { flag 1; // 设置标志 } } // 主循环 int main() { while (1) { if (flag) { flag 0; // 清标志 process_data(); // 处理数据临界区极小 } } }这里可行的原因单核无多线程flag是单字节写入ARM Cortex-M3 上对 aligned word 是原子的主循环读写flag时若被中断打断最多导致一次额外检查不会破坏数据一致性临界区只是“清标志”不涉及复杂共享结构。 注意这不是互斥锁而是事件标志。如果临界区是修改链表、缓冲区等仍需关中断✅ 更安全的裸机做法关中断void safe_update_shared_var(void) { __disable_irq(); // 关中断Cortex-M shared_var; __enable_irq(); // 开中断 }这利用了硬件原子性关中断期间不会被抢占比全局变量更可靠。三、总结场景能否用全局变量替代 mutex建议多线程 / 多核 / RTOS❌ 绝对不行必须用 mutex / semaphore裸机单核 中断 vs 主循环简单标志⚠️ 勉强可以但非互斥用 volatile 简单标志或关中断裸机单核 修改复杂共享数据❌ 不行必须关中断保护任何需要阻塞、可重入、跨进程的场景❌ 不行必须用 OS 提供的同步原语✅ 最佳实践有操作系统FreeRTOS、Linux 等→ 用mutex/semaphore。裸机单片机→ 对简单标志用volatile对临界区用关中断。永远不要用while(lock); lock1;这种方式模拟互斥锁 记住mutex不只是一个变量而是一套包含原子操作、内存屏障、调度器交互的完整机制。