信号量、互斥体和自旋锁实现原理初览--补充中

来源:互联网 发布:淘宝steam充值卡 编辑:程序博客网 时间:2024/06/06 04:23
本文重点在区分互斥锁和自旋锁的原理。
1. 互斥锁,假如进程A去抢锁,如锁已经被强占,那么进程A会被放入队列,接着进程的状态被改变,比如设为TASK_INTERRUPTIBLE,然后调用调度函数schedule(),后者将会把当前进程从cpu的运行队列中摘下,进程A进入睡眠。锁被释放,进程A将被唤醒。
而假如是自旋锁,A进程去抢自旋锁,锁已经被占后,A进程会不断的占用cpu,主动去查询(不像互斥锁,进入睡眠,被动等待被唤醒)自旋锁是否释放。

信号量/互斥体和自旋锁的区别

信号量/互斥体允许进程睡眠属于睡眠锁,自旋锁则不允许调用者睡眠,而是让其循环等待,所以有以下区别应用
1)、信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因而自旋锁适合于保持时间非常短的情况
2)、自旋锁可以用于中断,不能用于进程上下文(会引起死锁)。而信号量不允许使用在中断中,而可以用于进程上下文
3)、自旋锁保持期间是抢占失效的,自旋锁被持有时,内核不能被抢占,而信号量和读写信号量保持期间是可以被抢占的
另外需要注意的是
1)、信号量锁保护的临界区可包含可能引起阻塞的代码,而自旋锁则绝对要避免用来保护包含这样代码的临界区,因为阻塞意味着要进行进程的切换,如果进程被切换出去后,另一进程企图获取本自旋锁,死锁就会发生。
2)、在你占用信号量的同时不能占用自旋锁,因为在你等待信号量时可能会睡眠,而在持有自旋锁时是不允许睡眠的。


一、信号量

信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作:
   (1) 测试控制该资源的信号量。
   (2) 若此信号量的值为正,则允许进行使用该资源。进程将信号量减1。
   (3) 若此信号量为0,则该资源目前不可用进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1)。
   (4) 当进程不再使用一个信号量控制的资源时,信号量值加1。如果此时有进程正在睡眠等待此信号量,则唤醒此进程。

p 操作
在保证原子操作的前提下,先测试信号量数量是否大于0,如果是说明可以获得信号量,这种情况下需要先做--,以确保别的进程能否获得该信号量,然后函数返回,其调用者开始进入临界区。如果没有获得信号量,当前进程等待队列,开始睡眠。(注:将一个进程阻塞,一般的经过是先把进程放到等待队列中,接着改变进程的状态,比如设为TASK_INTERRUPTIBLE,然后调用调度函数schedule(),后者将会把当前进程从cpu的运行队列中摘下)

将当前进程赋给task,并利用其list成员将该变量的节点加入到以sem中的wait_list为头部的一个列表中,假设有多个进程在sem上调用down _interruptible,则sem的wait_list上形成的队列如下图:

v 操作
如果没有其他线程等待在目前即将释放的信号量上,那么只需将信号量数量++即可。如果有其他线程正因为等待该信号量而睡眠,那么调用__up.
这个函数首先获得sem所在的wait_list为头部的链表的第一个有效节点,然后从链表中将其删除,然后唤醒该节点上睡眠的进程。
由此可见,对于sem上的每次down_interruptible调用,都会在sem的wait_list链表尾部加入一新的节点。对于sem上的每次up调用,都会删除掉wait_list链表中的第一个有效节点,并唤醒睡眠在该节点上的进程。



主要参照博文:

http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html

原创粉丝点击