linux内核设计与实现读书笔记——内核同步

来源:互联网 发布:python赚外快 编辑:程序博客网 时间:2024/04/28 07:22

一、内核并发原因:

1)中断:由于中断可以打断当前正在执行的代码异步发生

2)软中断和tasklet:内核可以打断当前正在执行的代码,在任何时刻唤醒或者调度软中断和tasklet

3)内核抢占:被其它内核任务抢占

4)睡眠、用户空间同步:内核执行的进程睡眠引起程序调度

5)对称多处理器:多个处理器同时并发执行代码


中断安全代码(interrupt-saft):中断处理程序中避免并发访问的安全代码。

SMP安全代码(SMP-safe):对称多处理器的机器中能避免并发访问的安全代码。(CONFIG_SMP配置选项控制内核是否支持SMP,若单处理器可以选择不下载)

抢占安全代码(preempt-safe):在内核抢占时避免并发访问的安全代码。


锁的争用:高度争用的锁会成为系统的瓶颈,降低系统的性能。

扩展性:细粒度

二、内核同步方法

1、原子操作

内核提供:

对整数的原子操作接口:对atomic_t类型的数据进行处理,操作声明在<asm/atomic.h>

位操作的原子操作接口:定义在<asm/bitops.h>,针对普通内存地址,对给定地址的某位进行操作。(对应有非原子操作,速度更快)

2、自旋锁

1)原理:同一时刻至多被一个可执行线程持有,其它线程请求时忙等。不能被长时间占有,在短时间内进行轻量级加锁。

2)实现方法:定义在文件<asm/spinlock.h>,接口定义在<linux/spinlock>。

注意:

自旋锁不能递归。自旋锁是多处理器防止并发的保护机制,单处理器时则被当做内核抢占机制是否启用的开关。

中断处理程序中,在获取锁之前要禁止本地中断,避免双重请求死锁。spin_unlock_irqsave保存当前中断状态并禁止本地中断,store解锁。

下半部和进程上下文共享数据时候必须对上下文进行保护,加锁时需要禁止下半部执行;

中断可以抢占下半部执行 ,因此若共享数据,下半部还需要禁止中断;

不同类的共享数据的tasklet和多处理器上共享数据的软中断也许彼此注意锁的使用。

3)读、写自旋锁(共享、并发/排斥锁)

原理:多个读任务可以并发持有读者所,写的锁只能被一个写任务持有。

对读者更有利,因为写锁会等待所有读锁执行完毕。

3、信号量

睡眠锁,分为互斥信号量和计数信号量。

使用情况:锁被长时间持有,只能在进程上下文中获取信号量锁(中断上下文不能调度),可以在持有信号量时睡眠,因为可以睡眠所以不能占用自旋锁。

操作:P、V操作(down、up)

1)创建和初始化

semaphore类型,定义在<asm/semaphore.h>中,

2)使用

down_interruptible 获取指定信号量,如果不可用则设置进程为TASK_INTERRUPTABLE睡眠;

down_trylock以阻塞方式获取指定信号量,立即返回获取结果;

up释放指定信号量。

3)读写信号量 

rw_semaphore类型,定义在<asm/rwsem.h>中,是互斥信号量,只对写者互斥。

4、互斥体

mutex:任何可以睡眠的强制互斥锁。

在linux中为类似计数为1的信号量并提供了简洁的操作接口,使用有较多限制。

使用情况:一般优先使用互斥体,当限制条件不能满足,再考虑使用信号量。

5、完成变量

completion,定义在<linux/completion.h>中。

声明初始化之后,在指定的完成变量上,需要等待的任务调用wait_for_completion等待指定事件,发生事件的任务调用completion发送信号唤醒等待任务。

6、顺序锁

用于读写共享数据,通过序列计数器实现,对写者更有利。

适用情况:读者多、写着少,写优于读,数据简单。

7、屏障

操作以预定顺序执行:

rmb 读内存屏障;wmb 写内存屏障 ; mb两方等;barrier 组织编译器跨屏障对载入或者存储操作进行优化。



0 0
原创粉丝点击