1.并发概述
并发访问会导致竞态,应当避免。导致竞态的原因为一个程序访问临界资源时被非自愿抢
占,失去处理器,当调度一个新的进程随后也访问这个临界资源时就会导致竞态。
产生原因(如何失去处理器):
1.中断(被动放弃)
2.软中断(被动放弃)
3.抢占(假如内核配置为可抢占的话)
4.睡眠(主动放弃)
5.多处理器执行相同代码段(正真意义上的竞态)
所以归纳下,失去分处理器分两种,一种是自愿放弃如休眠,另一种是主动放弃如中断(包
括中断和软中断)。
2.内核的同步方法
同步和并行相对。并行指所有时间在同一时刻同时发生,同步是指在变化过程中保持一定
的相对关系。
1.原子操作(定义原子变量)
2.信号量(互斥信号量、读写信号量)
3.自旋锁(读写自旋锁等)
2.1三种方式的区别:
a.
原子操作适合保护较小数据,信号量和自旋锁适合保护相对较大的数据结构
b.
信号在不可用时会导致休眠,自旋锁则不会。自旋锁在不可用时,一直处于自选状态,
相当于死循环查询锁状态直到锁可用。所以自旋锁可以用在中断处理代码中,而信号量不可
以。但是自旋锁用在中断处理程序中应首先关闭中断。因为中断可以嵌套产生(不同中断好),
不关闭中断可能会导致死锁。
2.2自旋锁的竞态
使用自旋锁是为了保护临界资源,任务对临界资源的争抢转变成了对锁的争抢,所以自旋锁从
本质上来说就转变成了一种特殊的资源,对这种资源的争抢可能会导致死锁。比如2.1中的b中
的情况。所以在使用自旋的时候应该注意被保护的资源是否能被其他任务打断,并在那个任务
中争抢这个自旋锁,如何出现这种情况就应当十分小心!
例如,需要用自旋锁s保护r资源,r资源在进程上下文t和中断下半部b中共享(此出的中断下半部
采取的tasklet机制,即软中断)。则在进程上下文t中使用s锁的时候应当暂时禁止下半部b的运
行,因为假如在t进程上下文正在使用s锁的时候假如正好执行了下半部b,则在b中便会申请锁s,
而此时的s还在进程上下问t中,这便导致了死锁!
类似的情况还有很多,可根据抢占级别归纳。
内核中运行抢占级别如下排:
进程上下文<中断下半部=中断下半部<硬件中断<=硬件中断
进程上下文可被中断下半部打断;下半部能被硬件中断打断;下面分析各种情况下的处理
a.进程上下文能被中断下半部打断,所以在进程上下文和中断下半部共享数据的时候,在进程上下
文中应该暂时禁止中断下半部。
b.同类的tasklet不可能同时运行,所以共享数据也不需要保护。而不同类的tasklet在一个处理器上也
不可能出现抢占的情况,所以只需要用普通的自旋锁保护。所以在tasklet共享数据就不需要禁止下半
部。
c.中断下半部能被硬件中断打断,所以在中断下半部和硬件中断共享数据的时候,需要暂时禁止硬
件中断。
d.硬件中断可以嵌套(不同中断)产生(这种就是2.1b中的情况),所以在中断处理程序中应暂时关闭中断。
所以,使用锁的时候需要注意是否要1.禁止下半部2.禁止中断。
死锁
死锁产生的条件:
A、B任务都在需要请求资源,但是所请求的资源都被对方占用了,AB任务一直在相互等待对方占用的
资源并且在请求成功之前都不会先释放已占用的资源。
1.互斥。访问的资源是临界资源
2.请求与保持。任务在请求新资源之前保持对已有资源的占有
3.不可剥夺。一个资源只能被占用的任务释放,不能被其他进程剥夺
4.环路条件。任务之间产生环路,相互等待。
预防或者避免死锁的办法:
1.资源按照一定的数序申请,例如AB任务在运行过程中都需要申请资源S1和S2。那么,事先就先约定
无论是A任务还是B任务对S1、S2临界资源的申请顺序都是按照先申请S1,再申请S2。尽管A任务对临
界资源的使用顺序可能是先使用S2再使用S1,但依然按照先申请S1,再申请S2的顺序。
2.对临界资源的占用时间尽可能的短,用完马上释放
3.假如申请临界资源失败,应立即释放已占用的临界资源,或者等待一段时间假如还是失败则释放已占用
的临界资源。
4.打开内核调试选项,检测死锁条件,可以在死锁发生时输出相关信息
5.关中断,禁用任务调度。为任务创建原子运行环境。