自旋锁最多只能被一个可执行线程持有(读写自旋锁除外)。自旋锁不会引起调用者睡眠,如果一个执行线程试图获得一个已经被持有的自旋锁,那么线程就会一直进行忙循环,一直等待下去(一直占用 CPU ),在那里看是否该自旋锁的保持者已经释放了锁, " 自旋 " 一词就是因此而得名。
由于自旋锁使用者一般保持锁时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率远高于互斥锁。
信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用(因为中断的上下文不允许休眠)
自旋锁保持期间是抢占失效的(内核不允许被抢占) ,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或 SMP 的情况下才真正需要,在单 CPU 且不可抢占的内核下,自旋锁的所有操作都是空操作。
(问题:在单 CPU 可抢占内核中,如果一个进程请求自旋锁,那么他一直占用 CPU 循环等待自旋锁可用,那么原来占用自旋锁的进程得不到使用 CPU 的机会,怎么释放它自己占用的自旋锁呢?
回答:这种情况应该是在实际中不会发生的。因为考虑最开始的情况,一个进程需要自旋锁,而且这个时候自旋锁没有被占用,所以他加锁,进入临界区。因为这个时候内核已经被自旋锁设置成了非抢占式,所以正在运行的进程不会被调用处 CPU ,因此也不会再有其他的进程来请求这个已经被占用的自旋锁,当临界区代码处理完成后,释放了自旋锁,此时内核又被自旋锁设置成了可抢占模式,这个时候其他的进程可以被调度,因此可以再请求自旋锁等操作。因此问题中的情况应该在实际中不会发生。
注意,如果在一个已经对某个自旋锁加锁的进程的临界区中又申请对这个自旋锁加锁,则会导致进程自旋在那里,引起死机。)
一个执行单元要想访问被自旋锁保护的共享资源,必须先得到锁,在访问完共享资源后,必须释放锁。如果在获取自旋锁时,没有任何执行单元保持该锁,那么将立即得到锁;如果在获取自旋锁时锁已经有保持者,那么获取锁操作将自旋在那里,直到该自旋锁的保持者释放了锁。
因为自旋锁在同一时刻至多被一个执行线程持有,所以一个时刻只能有一个线程位于临界区,这就为多处理器提供了防止并发访问所需的保护机制,但是在单处理器上,编译的时候不会加入自旋锁。它仅仅被当作一个设置内核抢占机制是否被启用的开关( gx 自己的理解:在单内核可抢占式内核中,对自旋锁加锁导致禁止抢占,对自旋锁解锁导致恢复抢占模式。
-------- 自旋锁对信号量 ------------------------------------------------------
需求 建议的加锁方法
低开销加锁 优先使用自旋锁
短期锁定 优先使用自旋锁
长期加锁 优先使用信号量
中断上下文中加锁 使用自旋锁
持有锁是需要睡眠、调度 使用信号量