共享内存并发编程中的同步机制详解
1. 共享内存同步概述
在共享内存并发程序中,同步是主要的语义挑战。常见的同步形式有两种:互斥和条件同步。互斥确保在给定时间点只有一个线程执行关键代码段;条件同步确保给定线程在特定条件满足之前不会继续执行,例如特定变量达到给定值。虽然可以将互斥视为一种条件同步(即直到没有其他线程在其关键部分才继续),但这种条件需要所有现有线程达成共识,而条件同步通常无法提供这种共识。
在实现并行线程时,操作系统提供的进程需要使用互斥和条件同步来保护就绪列表和相关数据结构。互斥体现在一个进程在另一个进程修改就绪列表时不能读写它;条件同步体现在需要运行线程的进程必须等待就绪列表非空。
需要强调的是,我们通常不希望过度同步程序,因为这会消除并行机会,而我们通常希望最大化并行以提高性能。目标是仅提供足够的同步来消除可能导致程序产生错误结果的“不良”竞争条件。
2. 忙等待同步
2.1 忙等待条件同步
忙等待条件同步通常比较简单。如果能将条件表示为“位置 X 包含值 Y”,那么需要等待该条件的线程或进程可以在循环中读取 X,直到 Y 出现。硬件只需确保单个加载和存储指令是原子的。虽然提供这种原子性并非易事(内存和/或总线必须对处理器和设备的并发访问进行序列化),但几乎所有计算机都实现了这一点。
2.2 自旋锁
忙等待互斥更具挑战性,可通过自旋锁实现。以下是一些常见的自旋锁算法:
- Dekker 算法 :通常认为 Dekker 找到了第一个仅需加载和存储原子指令的双线程互斥算法。
- D