大话Linux内核中锁机制之信号量、读写信号量
大话Linux内核中锁机制之信号量、读写信号量
在上一篇博文中笔者分析了关于内存屏障、读写自旋锁以及顺序锁的相关内容,本篇博文将着重讨论有关信号量、读写信号量的内容。
六、信号量
关于信号量的内容,实际上它是与自旋锁类似的概念,只有得到信号量的进程才能执行临界区的代码;不同的是获取不到信号量时,进程不会原地打转而是进入休眠等待状态。它的定义是include\linux\semaphore.h文件中,结构体如图6.1所示。其中的count变量是计数作用,通过使用lock变量实现对count变量的保护,而wait_list则是对申请信号量的进程维护的等待队列。
图6.1 信号量的结构体定义
我们首先看下它是如何使用的,首先定义一个信号量,然后初始化信号量,它包括两种方法。如图6.2所示。方法1:简单的初始化,定义信号量的个数由val决定,实际上val值即是赋给信号量结构体中的count变量;方法2是直接将结构体中count值设置成1,此时信号量可用于实现进程间的互斥量。注意:对于信号量的初始化函数Linux最新版本存在变化,本文所采用的Linux版本已不存在如init_MUTEX和init_MUTEX_LOCKED等初始化函数,同时也更换了名字等,这点读者在阅读的时候需要下,因此笔者建议以后在编程中遇到需要使用信号量的时候尽量采用sema_init(struct semaphore *sem, int val)函数,因为这个函数就目前为止从未发生变化。
图6.2 信号量的初始函数
下面我们讨论如何获得信号量,它主要包括三个函数,第一个函数表示当信号申请不到时会进程会休眠;对于第二个函数来说,它表示如果当进程因申请不到信号量而进入睡眠后,能被信号打断,这里所说的信号是指进程间通信的信号,比如我们的Ctrl+C,但这时候这个函数的返回值不为0;第三个函数表示信号量无论是否获得,都将立即返回,但返回值会根据是否申请成功而定,同时这个函数也不会导致睡眠。最后的up函数,这个还是很好理解的,就是释放信号量,进而唤醒队列中的等待信号量的进程。函数如图6.3所展示一般。
图6.3 信号量的获得和释放函数
接下来笔者将举几个例子,依次如图6.4,图6.5所示。图6.4的例子仍是实现一个设备只能被一个进程打开。例子很简单,这里便不再细说,主要体现到底如何使用信号量。如图6.4所展示。
图6.4 信号量的使用示例
如图6.5实现的是进程间的同步问题。实际上,当把信号量的初始值为0,则可以实现同步了。正如图6.5所展示一般,对于执行单元A而言,如果执行单元B不执行up函数,执行单元A就因为申请不到进程而睡眠,直至up函数被调用,所以执行代码b前必须等到执行单元B执行完代码c。相信这个内容在操作系统课程都均有提及。
图6.5 信号量实现同步示例
讨论过示例后,相信读者对于信号量的使用有了比较好的了解。下面让我们来简单的讨论下它的实现机制。通过了解信号量的结构体,可以发现结构体中除了使用自旋锁机制外,就是count值的变化(这一点先前已提及)。它的源码如图6.6,图6.7所示。
图6.6 信号量down函数内核源码 图6.7 信号量up函数内核源码
从源码中可以看到信号量利用自旋锁的相关函数实现了对count变量的保护,通过判断变量是否大于0以及自增减来实现信号量的申请和释放。也是因为这一点,所以信号量能够实现同步机制。
另外,关于源码中的__down和__up函数的实现内容,它们其实是维护申请信号量的进程的链表队列(增加、删除操作),以及进程调度方面的一些信息(超时机制),从而让进程实现休眠。由于其中的源码量较为庞大,涉及的内容也较多,故这里不再深入讨论,感兴趣的可以查阅相关资料。
关于信号量的内容还有一点需要提及,我们知道信号量时进程级的,因此对于它的使用必然是当占用资源较长时间的时候。这点在使用信号量的使用需要重点考虑,反之,则容易影响程序的性能等。OK,至此,关于信号量的内容即讨论到此。
七、读写信号量
接下来笔者将讨论有关读写信号量的内容,这部分是较难的一部分,需分析较多的源码。同样,我们首先看下它主要能够做些什么:读写信号量与信号量的关系如同自旋锁与读写自旋锁的关系,它允许N个读操作同时访问共享资源,但最多只能有一个写操作。它的定义位置是在arch\x86\include\asm\rwsem.h以及kernel\rwsem.c中。关于它的结构体的定义,如图7.1所示。显然,它的结构体定义和信号量的结构体定义如出一辙。
图7.1 读写信号量的结构体实现
而后了解下它的具体使用方法,如图7.2所展示的函数。同其它锁机制类似,它所提供的接口函数也是较为简单,包括这些函数能实现的功能都差不了多少。
图7.2 读写信号量的接口函数
在了解读写信号量的定义和使用后,接下来读者将讨论的具体源码实现。它的具体实现是采用汇编实现,比较绕,需配合源码来一一说明,源码次序依次如图7.3至图7.8所示。为便于分析,下面源码只给出最为关键的内容。
对于图7.3所展示的内容主要是读写信号量中需要使用的一些宏定义,具体为何取这个值笔者就不大了解了,后续研究深入了可能会有所体会。
图7.3 读写自旋锁的内核源码
图7.4 读写自旋锁的内核源码
图7.5 读写自旋锁的内核源码
图7.4和同7.5所示源码主要体现了读锁和写锁的实现内容。实际上还是利用test指令检测count变量的值来实现。申请成功的内容好理解,其中的xadd指令表示将原操作数和目的操作数值相交换,而后相加保存入目的操作数。一旦读写信号量申请失败,则需要跳转到如图7.6,图7.7所示的源码中。其中图7.6,图7.7中所示的源码没多少内容,最后还是跳转到rwsem_down_read_failed和rwsem_down_write_failed函数中,通过汇编源码保存改变相应存储变量的寄存器,从而再次返回到C代码中,如图7.8所示的源码中。由于笔者能力有限,对于图7.8所示的源码内容中调用的rwsem_down_write_failed函数被没有研究透,故这里并未进一步深入研究。
至此,关于读写信号量的内容讨论基本结束,确实由于笔者能力有限,关于读写信号量的内容以及本博文的系列内容,读者可进一步深入研究,并欢迎讨论。共同进步。
图7.6 读写自旋锁的内核源码 图7.7 读写自旋锁的内核源码
图7.8 读写自旋锁的内核源码
出于文章篇幅的限制,本篇博文到此结束,后续将会给出《大话Linux内核中锁机制之完成量、互斥量》,感兴趣的读者可继续阅读后一篇博文。由于笔者水平所限,博文中难免有出错之处,欢迎读者指出,大家相互讨论,共同进步。
转载请注明出处:http://blog.sina.com.cn/huangjiadong19880706
大话Linux内核中锁机制之信号量、读写信号量的更多相关文章
- 大话Linux内核中锁机制之RCU、大内核锁
大话Linux内核中锁机制之RCU.大内核锁 在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核 ...
- 大话Linux内核中锁机制之完成量、互斥量
大话Linux内核中锁机制之完成量.互斥量 在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内 ...
- 大话Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁
大话Linux内核中锁机制之内存屏障.读写自旋锁及顺序锁 在上一篇博文中笔者讨论了关于原子操作和自旋锁的相关内容,本篇博文将继续锁机制的讨论,包括内存屏障.读写自旋锁以及顺序锁的相关内容.下面首先讨论 ...
- 大话Linux内核中锁机制之原子操作、自旋锁
转至:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 很多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其 ...
- 大话Linux内核中锁机制之原子操作、自旋锁【转】
转自:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实 ...
- Linux内核中锁机制之信号量、读写信号量
在上一篇博文中笔者分析了关于内存屏障.读写自旋锁以及顺序锁的相关内容,本篇博文将着重讨论有关信号量.读写信号量的内容. 六.信号量 关于信号量的内容,实际上它是与自旋锁类似的概念,只有得到信号量的进程 ...
- Linux内核中锁机制之RCU、大内核锁
在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核锁(BKL).文章的最后对<大话Linu ...
- Linux内核中锁机制之完成量、互斥量
在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等 ...
- Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁
在上一篇博文中笔者讨论了关于原子操作和自旋锁的相关内容,本篇博文将继续锁机制的讨论,包括内存屏障.读写自旋锁以及顺序锁的相关内容.下面首先讨论内存屏障的相关内容. 三.内存屏障 不知读者是是否记得在笔 ...
随机推荐
- Algorithm——整数反转
一.问题 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123 输出: 321 示例 2: 输入: -123 输出: -321 示例 3: 输入: 12 ...
- css控制一个元素点击后, 改变另外一个元素的状态
1.点击后改变子元素.myclass:active span{ color:#00f;} 此方式在ios下不生效,chrome下正常 2.改变下一个兄弟元素.myclass:active +span ...
- CSS属性之relative
0.相对定位relative特点 相对定位relative元素总是会占据位置,所占据的位置是在relative元素没有设置left/top/right/bottom属性时的位置: 相对定位relati ...
- 1 win10双系统安装ubuntu16.04和18.04(问题详细记录)
我从来不想在琐事上花功夫.就拿装系统来说,我感觉拿过来一个完全陌生的项目源码,看起来,都比装系统爽.我属于典型的逻辑思考男.喜欢畅游程序的海洋. 一直windows跑深度学习和tensorflow,有 ...
- 瞥了一眼js
JS打开超链接的几种形式1.window.open(''url'') 2.用自定义函数<script>function openWin(tag,obj){obj.target=" ...
- redis 序列化get、set获取不到原因记录
最近项目里面出现了个bug,把数据从数据库中读取后又存取到redis里面,之后再读取.奇怪的是,有一个 字段读取不到. public class Circle { private String id; ...
- eclipse 乱码问题总结
Eclipse 的控制台必须用GBK编码.所以条件1和条件4必须同时满足否则运行的还是乱码.才能保证不是乱码. 条件1,Window | Preferences | Workspace | T ...
- 将eChart图片利用POI导出到Excel
在使用POI进行将数据导出到Excel时, 若要将eChart在前端生成的统计图(如柱状图.折线图.饼图等)一并导出,使用POI在后台构建数据图比较复杂,因此我选择将eChart在前端的统计图的bas ...
- [翻译] MJParallaxCollectionView
MJParallaxCollectionView https://github.com/mayuur/MJParallaxCollectionView This is a parallax for t ...
- [翻译] JTBorderDotAnimation
JTBorderDotAnimation https://github.com/jonathantribouharet/JTBorderDotAnimation JTBorderDotAnimatio ...