基于原子的自旋锁认识与学习
我们不妨回归最朴素的思想,如果要做代码块的保护可以怎么实现。
显然,做一个全局的标记即可。在即将进入临界区前读取该标记是否可以通过,若可通过则修改此标记防止其他线程的通过。也就是我们常说的读改写操作。但寻常变量在上文中提到的计算机内存模型中显然是不可以实现这样的效果的。
因此这里就需要的是硬件的加持。通过在硬件层面通常会提供的一些原子操作的指令集,直接在处理器级别执行原子操作,而无需进行复杂的同步控制。
简单的用伪码表示该原子对象可以为:
object atomic function init() set(0) function clear() set(0) function test_and_set() -> bool if is 0 then set(1) return true else return false关于解锁比较简单,直接将原子对象重新置为空闲即可。
而上锁的操作是需要不断循环检测该标志是否已经被标记,这就是所谓的自旋。当然不断的去查询检测,其实让 CPU 执行了多余操作,因此可以让其在循环内部一定程度的让出任务调度权。
function lock() while !atomic.test_and_set() 直接自旋 or 让出任务调度权 function unlock() atomic.clear() function thread_fun() lock() 临界区操作 unlock()自旋锁的方案对单处理器和多处理器的环境下均适用。且是直接用循环判断上锁的,比较适合锁竞争较为激烈和等待时间较短的情况。
但其背后也有着一定的缺点。特别是在上锁时有着大量的无效检查。而直接让出调度权有会增加线程间的切换开销,其公平性取又决于系统的调度策略。
不过有了这个最基础的模型,我们可以在软件层面对其制定一系列的策略方案,从而将这些无法避免的缺点来最小化,并延申出功能更加丰富和强大的锁。
