阅读本文大概需要 2 分钟。
1、互斥锁(mutex)
同一时刻只能有一个线程获得互斥锁,其余线程处于挂起状态
优点:cpu利用最大化。它发现资源被锁住,请求就排队等候。线程切换到别处干活,直到接受到可用信号,线程再切回来继续处理请求
缺点:获取不到锁的时候会进入阻塞状态,从而进入内核态;当获取到锁的时候会从内核态切换到用户态,需要线程上下文切换; 线程的休眠和唤醒都是相当昂贵的操作,它们需要大量的CPU指令
加锁
void mutex_lock() {
lock(bus); //给总线加锁,防止其他核的线程访问到lock
if (mutex == 0) {
mutex = 1
return
} else {
block() // 调用系统函数将当前线程阻塞,进入内核态(内核调用)
goto mutex_lock
}
unlock(bus);
}
释放锁
void mutex_unlock() {
lock(bus); //给总线加锁,防止其他核的线程访问到lock
mutex = 0
wakeup() // 唤醒等待Mutex的线程(内核调用)
unlock(bus)
}
2、自旋锁
当某个线程获得自旋锁后,别的线程会一直做循环,尝试加锁
优点:自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快
缺点:1.长时间获取不到锁的话,cpu空转,耗cpu; 2. 不适用单核/单CPU的系统上,无法解锁
加锁
void spin_lock() {
// cas原子操作 CMPXCHG (cas是硬件支持的原子操作,不需要进入内核态)
while(!cas(state, 0, 1)) {
}
持有者 = 当前线程
}
释放锁
void spin_unlock() {
if(持有者 == 当前线程) {
持有者 = null
state = 1
} else {
throw Exception
}
}
3、混合锁:互斥锁+自旋锁
混合锁是先自旋锁一段时间或自旋多少次,再转成互斥锁
优点:互斥锁和自旋锁的折中方案,利用前二者优点,避免出现极端情况(自旋时间过长,互斥锁切换过多)
缺点:自旋多少时间、自旋多少次,这些策略很难把控。
本文深入解析了互斥锁、自旋锁及混合锁的工作原理与优缺点,互斥锁能最大化CPU利用率,但线程切换成本高;自旋锁减少上下文切换,适合轻量级同步,但可能造成CPU空转;混合锁结合两者优势,提高并发效率。

被折叠的 条评论
为什么被折叠?



