- 原子操作
- 原子操作可以保证指令以原子的方式执行--执行过程不被打断
- 针对整数的原子操作只能对atomic_t类型的数据进行处理。引入特殊数据类型的原因:
- 让原子函数只接受atomic_t类型的参数,确保原子操作只与这种特殊类型数据一起使用
- 保证该类型不会被传递给其他任何非原子函数
- 确保编译器不对相应的值进行访问优化
- 不同体系结构上实现原子操作时,使用atomic_t可以屏蔽其间的差异
- 使用atomic_t的代码只能将该类型的数据当做24位来用。原因是SPARC体系结构上,对原子操作缺乏指令级的支持,是通过32位int类型的低8位中嵌入了一个锁来实现。但这一限制已经不存在了。
- 原子整数操作列表,声明在<asm/atomic.h>中
原子整数操作列表 ATOMIC_INIT(int i) 在声明一个atomic_t变量时,将它初始化为i int atomic_read(atomic_t *v) 原子地读取整数变量v void atomic_set(atomic_t *v, int i) 原子地设置v值为i void atomic_add(int i, atomic_t *v) 原子地给v加i void atomic_sub(int i, atomic_t *v) 原子地给v减i void atomic_inc(atomic_t *v) 原子地给v加1 void atomic_dec(atomic_t *v) 原子地给v减i int atomic_sub_and_test(int i, atomic *v) 原子地给v减i,如果结果等于0返回真;否则返回假 int atomic_add_and_test(int i, atomic *v) 原子地给v加i,如果结果是负数返回真;否则返回假 int atomic_dec_and_test(atomic_t *v) 原子地给v减1,如果结果是0返回真;否则返回假 int atomic_inc_and_test(atomic_t *v) 原子地给v加1,如果结果是0返回真;否则返回假 - 对位这一级数据进行原子操作,声明在<asm/bitops.h>中
原子位操作列表 void set_bit(int nr, void *addr) 原子地设置addr所指对象的第nr位 void clear_bit(int nr, void *addr) 原子地清空addr所指对象的第nr位 void change_bit(int nr, void *addr) 原子地翻转addr所指对象的第nr位 int test_and_set_bit(int nr, void *addr) 原子地设置addr所指对象的第nr位,并返回原先的值 int test_and_clear_bit(int nr, void *addr) 原子地清空addr所指对象的第nr位,并返回原先的值 int test_and_change_bit(int nr, void *addr) 原子地翻转addr所指对象的第nr位,并返回原先的值 int test_bit(int nr, void *addr) 原子地返回addr所指对象的第nr位 - 内核还提供了一组非原子位操作,操作相同,不保证原子性,接口的名字是响应接口名字前缀多两个下划线
- 从指定地址开始搜索第一个被设置(或未被设置)的位:
- int find_first_bit(unsigned log *addr, unsigned int size)
- int find_first_zero_bit(unsigned log *addr, unsigned int size)
- 自旋锁
- 类型:spinlock_t lock;
- 与体系接口相关的代码定义在<asm/spinlock.h>中,实际需要用到的接口定义在<linux/spinlock.h>中
自旋锁方法列表 spin_lock() 获取指定的自旋锁 spin_lock_irq() 禁止本地中断并获取指定的锁 spin_lock_irqsave() 保存本地中断的当前状态,禁止本地中断,并获取指定的锁 spin_unlock() 释放指定的锁 spin_unlock_irq() 释放指定的锁,并激活本地中断 spin_unlock_irqrestore() 释放指定的锁,并让本地中断恢复到以前状态 spin_lock_init() 动态初始化指定的spinlock_t spin_trylock() 试图获取指定的锁;如果未获取,则返回非0 spin_is_locked() 如果指定的锁正在被获取,则返回非0,否则返回0
- 读写自旋锁
- 类型:rwlock_t lock;
read_lock() 获得指定的读锁
read_lock_irq() 禁止本地中断并获取指定读锁 read_lock_irqsave() 存储本地中断的当前状态,禁止本地中断并获取指定读锁 read_unlock() 释放指定的读锁 read_unlock_irq() 释放指定的读锁并激活本地中断 read_unlock_irqsave() 释放指定的读锁并将本地中断恢复到指定的前状态 write_lock() 获得指定的写锁
write_lock_irq() 禁止本地中断并获取指定写锁 write_lock_irqsave() 存储本地中断的当前状态,禁止本地中断并获取指定写锁 write_unlock() 释放指定的写锁 write_unlock_irq() 释放指定的写锁并激活本地中断 write_unlock_irqsave() 释放指定的写锁并将本地中断恢复到指定的前状态 write_trylock() 试图获得指定的写锁,如果写锁不可用则返回非0值 rw_lock_init() 初始化指定的rwlock_t rw_is_locked() 如果指定的锁当前已被持有则返回非0值,否则返回0
- 类型:rwlock_t lock;
-
信号量
- 是一种睡眠锁
- 类型:struct semaphore;
- 读写信号量
- 是互斥信号量
- 类型:struct rw_semaphore;
- 自旋锁和信号量的比较
- 完成变量
- 与信号量思想类似
- BKL
- BKL(大内核锁)是一个全局自旋锁
- 持有BKL的任务仍然可以睡眠。睡眠不会造成任务死锁,但是是不安全的
- 是递归锁,一个进程可以多次请求一个锁,并不会像自旋锁产生死锁现象
- 可以用在进程上下文
- BKL是有害的
- 内核抢占
- 顺序和屏障
- 编译器和处理器可能为了提高效率,对读写内存的指令重新排序
- 处理器提供机器指令来确保顺序要求,这些指令称做屏障
第九章 内核同步方法
最新推荐文章于 2022-08-25 22:24:56 发布