- 首页 > 生活广记 > >
linux内核设计与实现 LINUX内核源代码情景分析( 六 )
禁止和激活当前处理器中断:local_irq_disable,local_irq_enable禁止(屏蔽)指定中断线: disable_irq,disable_irq_nosync,enable_irq,synchronize_irq获取中断系统状态:asm/system.h中的irqs_disable判断是否处于中断上下文中:asm/hardirq.h中的in_interrupt六. 内核同步1. 基本概念
- 临界区:访问和操作共享数据的代码段
- 竞争条件:多个执行线程处于同一个临界区
- 同步:避免并发和防止竞争条件
- 为什么需要同步:用户程序会被调度程序抢占和重新调度
- 造成并发的原因有: 中断 内核抢占 睡眠及用户空间的同步 多处理器
- 同步问题的解决:加锁
- 什么数据需要加锁 内核全局变量 共享数据
- 死锁;所有线程都在等待对方释放锁,任何线程都无法继续进行
2. 内核同步方法2.1 原子操作
- 原子操作保证指令以原子方式执行
- 原子操作通常是内联函数,通过内嵌汇编指令完成
- 原子操作比其他同步方法给系统的开销小
- linux内核提供对整数和单独对位进行的原子操作
- 整数原子操作相关函数为asm/atomic.h文件中
- 位原子操作相关函数为asm/bitops.h
2.2 自旋锁
- 自旋锁(spin lock)最多只能被一个可执行线程持有 。如果锁未被占用,线程立刻可以得到 。如果被占用,会一直循环等待锁可用 。
- 自旋锁可用于防止多个线程同时进入临界区
- 自旋时特别浪费cpu,所以不应该被长时间持有
- 接口定义在,具体与体系结构相关的实现在
- linux中自旋锁不可用递归
- 自旋锁的使用
spinlock_t mr_lock = SPIN_LOCK_UNLOCKED;
//普通请求锁
spin_lock(&mr_lock);
//禁止中断请求锁
spin_lock_irqsave(&mr_lock);
//确保中断是激活的情况可用的方法
spin_lock_irq(&mr_lock)
/**临界区**/
spin_unlock_irq(&mr_lock)
spin_unlock_irqrestore(&mr_lock);
spin_unlock(&mr_lock)
- 自旋锁可以用在中断处理程序中(信号量不行,会导致休眠),在使用锁之前,要禁止本地中断,否则会导致死锁
2.3 读写自旋锁
- 锁用途可以明确分为读锁和写锁 。
- 一个或多个读任务可以并发的持有读者锁
- 用于写的锁只能被一个写任务持有,且此时不能并发读
- 读写锁使用
rwlock_t mr_rwlock = RW_LOCK_UNLOCKED;
read_lock(&mr_rwlock);
/**只读临界区**/
read_unlock(&mr_rwlock)
write_lock(&mr_rwlock)
/**读写临界区**/
write_unlock(&mr_rwlock)
2.4 信号量
- 信号量是一种睡眠锁
- 同一时刻允许任意数量的锁持有者
- 信号量数量为1时,称为二值信号量或互斥信号量
- 如果一个任务试图获取被占用的信号量,信号量会将其推入等待队列,让其睡眠 。当持有信号量的进程释放后,等待的任务被唤醒,获得信号量
- 信号量的特点 适合锁会被长时间持有的情况 锁被短时间持有,睡眠耗时可能比全部时间还长 会睡眠,不能在中断中调用 占有信号量时不能占用自旋锁 。自旋锁不允许休眠
- 信号量支持两个原子操作P和V,荷兰语的探查和增加
- 信号量相关文件:
- 使用信号量
//声明信号量
static DECLARE_SEMAPHORE_GENERIC(name, count);
//声明互斥量
static DECLARE_MUTET(name);
//以指针方式初始化信号量
sema_init(sem, count);
//以指针方式初始化互斥量
init_MUTET(sem);
//试图获得信号量
down_interruptible(&name)
//释放信号量
up(&name)
2.5 读写信号量
2.6 完全变量
2.7 Seq锁
- 提供一种简单的机制,用于读写共享数据
- 内部实现主要一个序列计数器
- 锁的初始化为0,写数据时,会得到锁,且序列值增加 。读数据之前和之后,序列号被读取,如果相同则没有被打断,如果为偶数则没有写操作发生
2.8 屏障
- 屏障(barriers)可以确保指令顺序执行,禁止指令重排序
- 重排序是因为现代处理器为了优化其传送管道,打乱了分派和提交指令的顺序
- rmb方法提供“读”内存屏障,rmb前面的载入操作不会排在rmb之后,反之亦然
- wmb方法提供“写”内存屏障,wmb前面的存储操作不会排在wmb之后 。