1. 自旋锁与互斥锁的本质区别
在并发编程中,自旋锁和互斥锁是两种最基本的同步原语。它们的核心差异在于等待锁时的行为模式:
1.1 自旋锁的忙等待机制
自旋锁采用了一种"不撞南墙不回头"的策略。当线程尝试获取锁失败时,它会持续不断地检查锁状态,直到成功获取为止。这种机制在代码层面表现为一个紧凑的循环:
cpp复制while (!try_lock()) {
// 空循环,持续尝试
}
这种实现方式有以下几个关键特点:
- CPU占用率100%:等待线程不会释放CPU资源
- 零上下文切换:线程始终保持运行状态
- 极低延迟:一旦锁释放,等待线程能立即感知
1.2 互斥锁的睡眠等待机制
互斥锁则采用了"知难而退"的策略。当获取锁失败时,线程会主动让出CPU,进入睡眠状态:
cpp复制if (!try_lock()) {
add_to_wait_queue(current_thread);
sleep(); // 主动让出CPU
}
这种机制的特点包括:
- CPU友好:等待线程不占用CPU资源
- 存在上下文切换开销:涉及线程状态保存和恢复
- 响应延迟:锁释放后需要唤醒等待线程
关键提示:选择锁类型时,临界区的执行时间是决定性因素。通常以5-10微秒为分界线,短于这个时间适合自旋锁,长于则适合互斥锁。
2. 自旋锁的底层实现剖析
2.1 原子操作的基础:CAS与TAS
自旋锁的核心依赖于CPU提供的原子指令,主要有两种实现方式:
- Test-And-Set (TAS):
cpp复制bool test_and_set(bool* lock) {
bool old = *lock;
*lock = true;
return old;
}
x86架构对应LOCK XCHG指令,原子性地交换内存和寄存器的值。
- Compare-And-Swap (CAS):
cpp复制bool compare_and_swap(int* value, int expected, int new_value) {
if (*value == expected) {
*value = n
解锁全文
加入我们的会员,获取最新、最热、最精彩的开发者技术内容