Linux内核中锁机制之完成量、互斥量
在上一篇博文中笔者分析了关于信号量、读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题。
八、完成量
下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等待另一个执行单元完成某事后方可执行,它是一种轻量级机制。事实上,它即是为了完成进程间的同步而设计的,故而仅仅提供了代替同步信号量的一种解决方法,初值被初始化为0。它在include\linux\completion.h定义。
如图8.1所示,对于执行单元A而言,如果执行单元B不执行complete函数,执行单元A就会因为申请不到进程而睡眠,直至complete函数在执行单元B中被调用,所以执行代码b前必须等到执行单元B执行完代码c。这一点同信号量同步的机制类似,只是调用的函数不同而已。
图8.1 完成量的使用示例
下面笔者将讨论下它的实现机制。笔者从内核中找出了相关的源码,依次如下图8.2至图8.5所示。由于图8.5中的do_wait_for_common函数实现较多,故给出的是删节后的函数大概框架图。
图8.2 完成量的结构体定义
图8.2展示了完成量的结构体定义,done变量是完成量要保护的对象,wait则是申请完成量的进程的等待队列。从图8.3中我们可以看出当初始化完成量变量时,done变量被初始化成0,对比利用信号量实现同步的内容,可以发现它们是相一致的。
图8.3 完成量的内核源码
配合图8.1中的完成量源码,我们发现现在对于执行单元A,它现在执行完代码a后调用wait_for_common函数,这个函数的源码实现如图8.5所示。可以看出,它其实即是对done变量作判断,若done变量没有大于0,则它一直处于while循环中。此时,若是执行单元B执行完代码c后,执行complete函数,此时,观察图8.4中的complete函数实现,可以发现它对done变量值增1。此时,wait_for_common函数便会退出while循环,同时将done值减1,以表示申请完成量成功。
图8.4 完成量的内核源码
图8.5 完成量的内核源码
至此,关于完成量的内容即讨论到此,总体来说,完成量的内容还是较为简单的。后续笔者将会讨论有关互斥量的使用和实现。
九、互斥量
下面笔者将讨论互斥量的相关内容。首先互斥量的提出主要是由于进程在使用信号量后开销较大。互斥量提供了两种机制,包括经典互斥量和实时互斥量两种,依次在文件include\linux\mutex.h (经典互斥量)和include\linux\rtmutex.h (实时互斥量)中定义,下面我们来看下它的一些具体内容。
首先讨论关于经典互斥量的内容,它的结构体定义如图9.1所示。结构体中我们重点关注count、wait_lock、wait_list等变量。和读写信号量的定义相类似。
图9.1 经典互斥量的结构体定义
另外,关于它的用法和先前的一些锁机制其实都差不多,具体函数即把加解锁的函数换成mutex_lock和mutex_unlock等,而它的内部的源码实现是建立上原子锁和自旋锁的相关机制之上,同时还有一些关于队列维护的一些内容,这些内容,我们可从它的结构体定义即可简单看出,这里不太深入讨论了,感兴趣的话可以看上面提示的两个文件。
下面我们来介绍实时互斥锁的内容,在介绍这个内容之前,我们先来看一个有趣的问题,就是无限制优先级反转问题,这个问题曾经引起了美国的火星探测器的故障(后续介绍)。
下面具体讨论到底什么是无限制优先级反转问题,总体来说,图9.2至图9.7展示了整个问题发生的过程。首先当前有一个执行单元C获取了一个互斥量,正在所保护的临界区中执行,且不打算在短时间内推出。此时,系统中“跑来”执行单元A申请这个互斥量,由于执行单元C正在使用这个互斥量,故A只能等待C执行完,尽管A的优先级远高于C(多么无奈)。这时候,又冒出一个执行单元B,它的优先级介于A和C之间。由于系统的一个中断的发生,导致执行单元B直接抢占C进程而开始执行互斥量所在的临界区。但这种情况实际上也抢占了执行单元A,尽管执行单元A的优先级高于执行单元B(A就是个悲剧)。如果执行单元B继续执行,那么执行单元A将等待更长的时间,因为执行单元C被执行单元B抢占,所以它也只能等待执行单元B完成其操作。因此看起来就像执行单元B的优先级高于执行单元A一样。这种情况就是我们所说的无限制优先级反转问题。
图9.2 执行单元C访问临界区 图9.3 执行单元A等待C完成其操作
图9.4 B抢占C而执行临界区 图9.5 B在临界区中执行
图9.6 B执行完后C继续执行临界区 图9.7 A最终执行临界区
下面简单提及下美国火星探测器的故障问题:1997年的美国的火星探测器(探测器使用的是Vxworks系统)遇到一个优先级反转问题引起的故障。首先火星探测器有一个信息总线,有一个高优先级的总线任务负责总线数据的存取,访问总线都需要通过一个互斥锁(共享资源出现了);还有一个低优先级的,运行不是很频繁的气象搜集任务,它需要对总线写数据,也就同样需要访问互斥锁;最后还有一个中优先级的通信任务,它的运行时间比较长。平常这个系统运行毫无问题,但是有一天,在气象任务获得互斥锁往总线写数据的时候,一个中断发生导致通信任务被调度就绪,通信任务抢占了低优先级的气象任务,而无巧不成书的是,此时高优先级的总线任务正在等待气象任务写完数据归还互斥锁,但是由于通信任务抢占了CPU并且运行时间比较长,导致气象任务得不到CPU时间也无法释放互斥锁,从而使本来是高优先级的总线任务也无法执行,总线任务无法及时执行的后果被探路者认为是一个严重错误,最后就是整个系统被重启。事实上,Vxworks系统允许优先级继承,然而遗憾的是工程师们将这个功能给停止了,从而使火星探测器就此悲剧了。
由于无限制优先级反转问题无法使用经典互斥量来解决,理由是经典互斥量中的队列并没有实现将等待进程按优先级排队。实时互斥量就此因运而生,我们们可以简单看下它的结构体定义,如图9.8所示。
图9.8 实时互斥量的结构体定义
既然经典互斥量不能解决将等待进程按优先级排队问题,因此对于实时互斥量,它的实现关键即是wait_list的实现,看此变量的定义类型为plist_head,便可一目了然。在plist_head链表操作数,它即采用了优先级继承关系将等待进程队列按进程优先级方式排队。这里优先级继承表示为如果高优先级的进程阻塞在互斥量上,该互斥量当前由低互斥量拥有,那么将低优先级的临时提升到高优先级。
至此,关于互斥量的内容即讨论到此,经过上述的讨论,相信读者对于互斥量的内容有了比较好的了解,后续《大话Linux内核中锁机制之RCU、大内核锁》将会重点给出有关RCU机制的相关分析,感兴趣的读者可继续阅读后一篇博文。由于笔者水平所限,博文中难免有出错之处,欢迎读者指出,大家相互讨论,共同进步。
Linux内核中锁机制之完成量、互斥量的更多相关文章
- 大话Linux内核中锁机制之完成量、互斥量
大话Linux内核中锁机制之完成量.互斥量 在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内 ...
- Linux内核中锁机制之信号量、读写信号量
在上一篇博文中笔者分析了关于内存屏障.读写自旋锁以及顺序锁的相关内容,本篇博文将着重讨论有关信号量.读写信号量的内容. 六.信号量 关于信号量的内容,实际上它是与自旋锁类似的概念,只有得到信号量的进程 ...
- 大话Linux内核中锁机制之信号量、读写信号量
大话Linux内核中锁机制之信号量.读写信号量 在上一篇博文中笔者分析了关于内存屏障.读写自旋锁以及顺序锁的相关内容,本篇博文将着重讨论有关信号量.读写信号量的内容. 六.信号量 关于信号量的内容,实 ...
- Linux内核中锁机制之RCU、大内核锁
在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核锁(BKL).文章的最后对<大话Linu ...
- Linux内核中锁机制之原子操作、自旋锁
很多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实是由于操作系统中存在多进程对共享资源的并发访问,从而引起了进程间的竞态.这其中包括了我们所熟知的SMP系统,多 ...
- 大话Linux内核中锁机制之RCU、大内核锁
大话Linux内核中锁机制之RCU.大内核锁 在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核 ...
- 大话Linux内核中锁机制之原子操作、自旋锁
转至:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 很多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其 ...
- 大话Linux内核中锁机制之原子操作、自旋锁【转】
转自:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实 ...
- Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁
在上一篇博文中笔者讨论了关于原子操作和自旋锁的相关内容,本篇博文将继续锁机制的讨论,包括内存屏障.读写自旋锁以及顺序锁的相关内容.下面首先讨论内存屏障的相关内容. 三.内存屏障 不知读者是是否记得在笔 ...
随机推荐
- MSSQL工作中常用的小技巧
大概看了一下有接近二十天自己没有写博客了,一来是因为国庆之前公司工作总会比较繁杂一点,国庆自己也需要休息,二来是因为学习一些新的东西,公司写了一天SQL回家看了看以前的笔记,感觉还挺不错,贴出来供大家 ...
- linux程序调试命令addr2line之入门简单介绍(本文先不聊gdb调试)
addr2line有什么作用呢? 可别小瞧它, 它能够定位到代码出错的位置. 以下, 我们来看看这个简单的代码: #include <stdio.h> int main() { int * ...
- Spark性能优化(2)——广播变量、本地缓存目录、RDD操作、数据倾斜
广播变量 背景 一般Task大小超过10K时(Spark官方建议是20K),需要考虑使用广播变量进行优化.大表小表Join,小表使用广播的方式,减少Join操作. 参考:Spark广播变量与累加器 L ...
- 虚拟机配置Cognos报错CFG-ERR-0106
在虚拟机中安装Cognos 之后,启动了好多次,都启动失败,如下图所示,错误如下图所示 已确保已下信息设置正确 1:内容库配置OK 2:Java_home OK 3:字符集OK ----------- ...
- jmeter-The JVM should have exitted but did not
修改 jmeterengine.force.system.exit=true
- UE如何使用正则表达式
1 基本概念 元字符: 元字符 说明 . 匹配除换行符以外的任意字符 \w 匹配字母或数字或下划线或汉字 \s 匹配任意的空白符() \d 匹配数字 \b 匹配单词的开始或结束 \W 匹配任意不是字母 ...
- java编程思想 第四版 第六章 个人练习
欢迎加群:239063848 进群须知:本群仅用于技术分享与交流.问题公布与解答 禁止闲聊.非诚勿扰 练习1:(1)在某个包中创建一个类,在这个类所处的包的外部创建该类的一个实例. import mi ...
- UVA 10026 Shoemaker's Problem 鞋匠的难题 贪心+排序
题意:鞋匠一口气接到了不少生意,但是做鞋需要时间,鞋匠只能一双一双地做,根据协议每笔生意如果拖延了要罚钱. 给出每笔生意需要的天数和每天的罚钱数,求出最小罚钱的排列顺序. 只要按罚款/天数去从大到小排 ...
- windows登陆密码破解方法之一
网上的一些人让别人进入命令提示符安全模式,我比较奇怪如果没有密码怎么进去?能进去干嘛还要进去? 本笨方法的原理主要是利用登陆界面的一些程序入口,把它当成后门来使用,比如win7登陆界面上除了输密码的地 ...
- 腾讯云-Linux 基础入门
Linux 基础入门 目录操作 任务时间:5min ~ 10min 创建目录 使用 mkdir 命令创建目录 mkdir $HOME/testFolder # $HOME 当前用户的家目录 root ...