【注意】最后更新于 October 10, 2019,文中内容可能已过时,请谨慎使用。
中断与锁(第7 ,8,9,10 章节)
1. 延迟处理机制
中断特点
- 中断处理程序不是可重入的。因为屏蔽了中断,根本不会发生切换。同类自旋锁是不可重入的
- 中断处理进程,只能采用自旋锁(短期互斥原语),不能长期互斥原语(这会导致进程睡眠)
- 随时都可能发生,异步的。
中断处理程序 —ksoftirqd
1
2
3
4
5
6
7
8
9
|
ps -ef |grep ksoftirqd
root 3 2 0 2018 ? 00:00:06 [ksoftirqd/0]
root 29 2 0 2018 ? 00:00:01 [ksoftirqd/1]
root 34 2 0 2018 ? 00:00:00 [ksoftirqd/2]
root 39 2 0 2018 ? 00:00:00 [ksoftirqd/3]
root 44 2 0 2018 ? 00:00:00 [ksoftirqd/4]
root 49 2 0 2018 ? 00:00:00 [ksoftirqd/5]
root 54 2 0 2018 ? 00:00:00 [ksoftirqd/6]
root 59 2 0 2018 ? 00:00:00 [ksoftirqd/7]
|
流程
结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/* 用于描述一个软中断 */
struct softirq_action
{
/* 软中断的处理函数 */
void (*action)(struct softirq_action *);
};
/* 6个软中断描述符都保存在此数组 */
static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
struct tasklet_struct
{
struct tasklet_struct *next; /* 指向链表下一个tasklet */
unsigned long state; /* tasklet状态 TASKLET_STATE_SCHED表示处于链表中,TASKLET*/
/* _STATE_RUN表示正在运行*/
atomic_t count; /* 禁止计数器,调用tasklet_disable()会增加此数,tasklet*/
/* enable()减少此数 */
void (*func)(unsigned long); /* 处理函数 */
unsigned long data; /* 处理函数使用的数据 */
};
struct tasklet_head {
struct tasklet_struct *head;
struct tasklet_struct **tail;
};
|
2. 锁
读写锁 (ReentrantReadWriteLock)
特点
- 可重入互斥锁( reentrant mutex )
同一线程对其多次加锁不会产生死锁。可重入互斥锁也称递归互斥锁
自旋锁
特点
若有同一线程两调用lock() ,会导致第二次调用lock位置进行自旋,产生了死锁
————————————————华丽分隔符————————————————————————
可重入性
若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(reentrant或re-entrant)的。
即当该子程序正在运行时,执行线程可以再次进入并执行它,仍然获得符合设计时预期的结果。
若一个函数是可重入的,则该函数应当满足下述条件:
- 不能含有静态(全局)非常量数据。
- 不能返回静态(全局)非常量数据的地址。
- 只能处理由调用者提供的数据。
- 不能依赖于单实例模式资源的锁。
- 调用(call)的函数也必需是可重入的。
啥意思 就是
你在执行一个函数的时候,切换出去别人在执行同样的函数,或者其他函数。而不出问题
————————————————华丽分隔符————————————————————————
改造后的自旋锁
例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public class SpinLock {
private AtomicReference<Thread> owner =new AtomicReference<>();
private int count =0;
public void lock(){
Thread current = Thread.currentThread();
if(current==owner.get()) {
count++;
return ;
}
//compareAndSet(Thread expect, Thread update)
//自旋锁的自旋就是体现在这里
while(!owner.compareAndSet(null, current)){
}
}
public void unlock (){
Thread current = Thread.currentThread();
if(current==owner.get()){
if(count!=0){
count--;
}else{
owner.compareAndSet(current, null);
}
}
}
}
注意两点:
1. 修改之后,就可以重复进入代码区域了
|
中断与信号(11章节)
信号的特点
可重入性是函数编程语言的关键特性之一
- 信号处理函数中只能调用可重入函数,而不能调用不可重入函数
塔山