互斥锁与自旋锁

1、互斥锁原理

在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为"
互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

互斥锁,是一种信号量,常用来防止两个进程或线程在同一时刻访问相同的共享资源。可以保证以下三点:

(1)原子性:把一个互斥量锁定为一个原子操作,这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程在同
一时间可以成功锁定这个互斥量。

(2)唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量。

(3)非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。

从以上三点,我们看出可以用互斥量来保证对变量(关键的代码段)的排他性访问。

2、自旋锁原理

它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。

自旋锁有几个重要的特性:

1、被自旋锁保护的临界区代码执行时不能进入休眠。

2、被自旋锁保护的临界区代码执行时是不能被被其他中断中断。

3、被自旋锁保护的临界区代码执行时,内核不能被抢占。从这几个特性可以归纳出一个共性:被自旋锁保护的临界区代码执行时,它不能因为任何原因放弃处理器。

 

3、死锁

自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是
否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。其作用是为了解决某项资源的互斥使用。因为自旋锁不会引起调用者睡眠,所以自旋锁的效率远 高于互斥锁。虽然它的效率比互斥锁高,但是它也有些不足之处: 

1、自旋锁一直占用CPU,他在未获得锁的情况下,一直运行--自旋,所以占用着CPU,如果不能在很短的时
间内获得锁,这无疑会使CPU效率降低。

2、在用自旋锁时有可能造成死锁,当递归调用时有可能造成死锁,调用有些其他函数也可能造成死锁,如
copy_to_user()、copy_from_user()、kmalloc()等。

因此我们要慎重使用自旋锁,自旋锁只有在内核可抢占式或SMP的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。自旋锁适用于锁使用者保持锁时间比较短的情况下。

造成死锁的几个可能的原因

1、试图递归地获得自旋锁必然会引起死锁:递归程序的持有实例在第二个实例循环,以试图获得相同自旋锁时,不会释放此自旋锁。在递归程序中使用自旋锁应遵守下列策略:递归程序决不能在持有自旋锁时调用它自己,也决不能在递归调用时试图获得相同的自旋锁。此外如果一个进程已经将资源锁定,那么,即使其它申请这个资源的进程不停地疯狂“自旋”,也无法获得资源,从而进入死循环。

2、进程得到自旋锁后阻塞,睡眠:

在获得自旋锁之后调用copy_from_user()、copy_to_ser()、和kmalloc()等有可能引起阻塞的函数。

3、中断中没有关中断,或着因为申请未释放的自旋锁

在中断中使用自旋锁是可以的,应该在进入中断的时候关闭中断,不然中断再次进入的时候,中断处理函数会自旋等待自旋锁可以再次使用。或者在进程中申请了自旋锁,释放前进入中断处理函数,中断处理函数又申请同样的自旋锁,这将导致死锁。

3.1   案例

在驱动程序中,我们的驱动程序正在执行,并且已经获得了一个锁,这个锁控制着对设备的访问。在拥有这个锁的时候,设备产生了一个中断,它导致中断处理函数被调用,而中断处理函数在访问这个设备之前,也要获得这个锁,由于自旋锁操作是不能休眠的,因此处理器将永远的自旋下去,形成死锁。

4、 自旋锁三种状态

自旋锁保持期间是抢占失效的(内核不允许被抢占)。

1、单CPU且内核不可抢占:

自旋锁的所有操作都是空。不会引起死锁,内核进程间不存在并发操作进程,进程与中断仍然可能共享数据,存在并发操作,此时内核自旋锁已经失去效果。

2 、单CPU且内核可抢占:

当获得自旋锁的时候,禁止内核抢占直到释放锁为止。此时可能存在死锁的情况是参考自旋锁可能死锁的一般情况。

禁止内核抢占并不代表不会进行内核调度,如果在获得自旋锁后阻塞或者主动调度,内核会调度其他进程运行,被调度的内核进程返回用户空间时,会进行用户抢占,此时调用的进程再次申请上次未释放的自旋锁时,会一直自旋。但是内核被禁止抢占,从而造成死锁。

内核被禁止抢占,但此时中断并没被禁止,内核进程可能因为中断申请自旋锁而死锁。

3 、多CPU且内核可抢占:

这才是是真正的SMP的情况。当获得自旋锁的时候,禁止内核抢占直到释放锁为止

时间: 2024-12-25 20:06:49

互斥锁与自旋锁的相关文章

原子属性与非原子属性,互斥锁与自旋锁介绍

nonatomic 非原子属性 非线程安全,适合内存小的移动设备(手机,平板...) atomic 原子属性(线程安全,但需要消耗大量资源)针对多线程设计的,为默认值,保证同一时间只有一个线程能够写入;本身就是一把自旋锁;单写多读,单个线程写入,多个线程读取 注意:当重写属性的get与set方法时需要在@implementation后添加:@synthesiae 属性名 = _属性名; 互斥锁与自旋锁对比 互斥锁:如果发现其他线程正在执行锁定代码,线程会进入休眠(就绪状态),等其他线程时间到打开

信号量、互斥体和自旋锁小结

概述 linuxn内核同步机制几种常用的方式,面试经常会被问道,这里做一个小结 [1]信号量 [2]互斥体 [3]自旋锁 [4]区别 1.信号量(semaphore) 又称为信号灯,本质上,信号量是一个计数器,用来记录对某个共享资源的存取情况,一般共享资源通过以下步骤 (1) 测试控制该资源的信号量(n). (2) 若此信号量的值为正,则允许进行使用该资源.进程将信号量减1. (3) 若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1). (4)

信号量,互斥锁,自旋锁

个人理解: 信号量(进程间的通信机制(单一个数的信号),与消息邮箱,消息队列,机理类同,量不同,)用信号量肯定掉cpu: 自旋锁:保护区域不掉cpu,持续查找,等待(不可用时域长状态): 切记: 时域范围: 在进程间的通信机制函数状态 ∩ 锁 = 0: 互斥锁与自旋锁 互斥锁:线程会从sleep(加锁)-->running(解锁),过程中有上下文的切换,cpu的抢占,信号的发送等开销. 自旋锁:线程一直是running(加锁-->解锁),死循环检测锁的标志位,机制不复杂. 自旋锁 == whi

信号量、互斥体和自旋锁

http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html 信号量.互斥体和自旋锁 一.信号量 信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是共享内存方式的进程间通信.本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况.一般说来,为了获得共享资源,进程需要执行下列操作:  (1) 测试控制该资源的信号量.  (2) 若此信号量的值为正,则允许进行使用该资源.进程将信号量减1.

阻塞锁,非阻塞锁,自旋锁,互斥锁

1.阻塞锁 多个线程同时调用同一个方法的时候,所有线程都被排队处理了.让线程进入阻塞状态进行等待,当获得相应的信号(唤醒,时间) 时,才可以进入线程的准备就绪状态,准备就绪状态的所有线程,通过竞争,进入运行状态. public class Lock{ private boolean isLocked = false; public synchronized void lock() throws InterruptedException{ while(isLocked){ //当其他线程进来,即处

Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等(转)

Java 中15种锁的介绍 在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 公平锁 / 非公平锁 可重入锁 / 不可重入锁 独享锁 / 共享锁 互斥锁 / 读写锁 乐观锁 / 悲观锁 分段锁 偏向锁 / 轻量级锁 / 重量级锁 自旋锁 上面是很多锁的名词,这些分类并不是全是指锁的状态,有的指锁的特性,有的指锁的设计,下面总结的内容是对每个锁的名词进行一定的解释. 公平锁 / 非公平锁 公平锁 公平锁是指多个线程按照申请锁的顺序来获取锁. 非公

Java锁---偏向锁、轻量级锁、自旋锁、重量级锁

之前做过一个测试,反复执行过多次,发现结果是一样的: 1. 单线程下synchronized效率最高(当时感觉它的效率应该是最差才对): 2. AtomicInteger效率最不稳定,不同并发情况下表现不一样:短时间低并发下,效率比synchronized高,有时甚至比LongAdder还高出一点,但是高并发下,性能还不如synchronized,不同情况下性能表现很不稳定: 3. LongAdder性能稳定,在各种并发情况下表现都不错,整体表现最好,短时间的低并发下比AtomicInteger

通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!

网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底层实现浅尝辄止,但是在需要时能够知道去查什么. 首先要打消一种想法,就是一个锁只能属于一种分类.其实并不是这样,比如一个锁可以同时是悲观锁.可重入锁.公平锁.可中断锁等等,就像一个人可以是男人.医生.健身爱好者.游戏玩家,这并不矛盾.OK,国际惯例,上干货. 〇.synchronized与Lock

写文章 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!

网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底层实现浅尝辄止,但是在需要时能够知道去查什么. 首先要打消一种想法,就是一个锁只能属于一种分类.其实并不是这样,比如一个锁可以同时是悲观锁.可重入锁.公平锁.可中断锁等等,就像一个人可以是男人.医生.健身爱好者.游戏玩家,这并不矛盾.OK,国际惯例,上干货. 〇.synchronized与Lock