全部博文(436)
分类: LINUX
2013-03-06 21:11:00
《深入理解Linux内核》第五章---内核同步 读书报告
我们可以把内核看作是不断请求进行相应的服务器,而内核的各个部分采取交错执行的方式,即内核各部分交错执行,产生了竞争条件,所以需要同步技术来解决。因此本章主要介绍了内核中所实现的基本同步机制。
一、 内核抢占
定义:如果进程执行内核函数时(内核态运行),允许发生内核切换。
特点:在内核态运行的进程,可能在执行内核函数期间被另外一个进程取代。
使用内核抢占的目的:减少用户态进程的分派延迟(dispatch latency),即从进程变为可执行状态到它实际开始运行之间的时间间隔。
二、 同步原语
Linux内核有多种内核同步技术:每CPU变量(Per-CPU),原子操作、内存屏障、自旋锁、信号量、顺序锁、本地中断禁止、本地软中断(可延迟函数)禁止、读-拷贝-更新(RCU)
1)每CPU变量
定义:每CPU变量主要是数据结构的数组,系统的每个CPU对应数组的一个元素。
总的原则:内核控制路径应该在禁用抢占的情况下访问Per-CPU变量。
2)原子操作
若干汇编语言指令具有 “读 - 修改 - 写”类型,访问存储器单元两次,第一次读原值,第二次写新值。 这种技术主要针对单变量的数据,CPU对一个变量的访问可能不是原子的,但是采用atomic_t类型的原子变量,内核可以保证原子的访问变量。但操作这种变量只能用内核提供的函数,不能单独的操作。
存储器仲裁器:对访问RAM芯片的操作进行串行化的硬件电路。
避免由于“读 - 修改 - 写”类型引起竞争的方法:确保这样的操作在芯片级是原子的。避免其他CPU访问同一存储单元。
3)优化和内存屏障
优化屏障:保证编译器不会混淆在屏障操作之前的汇编指令与屏障之后的汇编指令。内存屏障:保证在屏障之后的操作开始执行之前,屏障之前的操作已经完成。
(1)编译器优化,用barrier()优化屏障 防止
(2)CPU取指优化,用 wmb/rmb等防止
4)自旋锁
自旋锁:如果内核控制路径发现锁由运行在另一个CPU的内核控制路径”锁着“,就在当前CPU”旋转“,反复执行一条紧凑的循环指令,直到锁被释放。
一般来说:自旋锁所保护的每个临界区都是禁止内核抢占的。但是分为:具有内核抢占的spin_lock宏;非抢占式内核中的spin_lock宏。
spin_unlock宏: movb $1,slp->slock
其他的同步技术有:
5)读/写自旋锁
读/写自旋锁:这个锁是为了增加内核的并发能力。只要没有内核控制路径对数据进行修改,允许多个控制路径同时读取同一数据结构。读/写操作具有相同的优先级。
6)顺序锁(seqlock)
顺序锁(seqlock): 与读写锁类似,但是读/写操作有不同的优先级,读操作的优先级低于写操作。也就是一个读程序持有锁的情况下可以被一个写程序打断。
7)RCU(读-拷贝-更新)
RCU(读-拷贝-更新):保护被多个CP读的数据结构而设计的同步技术。写者更新数据结构时,它间接引用指针并生成整个数据结构的副本;写者修改这个副本;
静止状态(quiescent state),CPU经历以下一种状态即为静止状态:
a)CPU执行进程切换
b)CPU开始在用户态执行
c)CPU执行空循环
8)信号量 :使进程可以睡眠的锁。当进程或得不到锁的时候睡眠,当释放锁的时候,唤醒睡在锁上的进程。
9)读/写信号量
10)补充原语
11)禁止本地中断
12)禁止和激活可延迟函数
临界区是一段代码,在其他的内核控制路径能够进入临界区前,进入临界区的的内核控制路径必须全部执行完这段代码。
总结:编写驱动程序中要灵活运用内核中的同步技术,这样才能编写出并发度高,稳定健壮的驱动程序。首先要确定哪些部分是需要保护的,这就需要分析访问数据的代码可能有几个内核控制路径并行或者并发执行,结合各个同步技术的特点灵活应用,一般而言能要同步的就不要同步,能不加锁的就不加锁,因为内核同步必然会引起一定的性能损失。
感想:由于此章还涉及中断与异常方面的内容,所以理解起来还有些困难,所以要结合之前的章节一起看效果会更好。
问题:
为什么在单处理器系统中,永远不会发生内存总线窃用的情况。