kernel 并发和竞争

信号量和互斥体
kmalloc可能会引发睡眠

信号量(减少信号量值获取锁定状态)
信号量就是一种睡眠锁
如果一个任务试图获取一个已经被占用的信号量,他会被推入等待队列,让其进入睡眠。此刻处理器重获自由,去执行其他的代码。
当持有的信号量被释放,处于等待队列的任务将被唤醒,并获取到该信号量。
<asm/semaphore.h>
初始化信号量方法1
struct semaphore sem;
sema_init(&sem, val);
初始化信号量方法2
DEFINE_SEMAPHORE(sem)
初始化后必须先解锁
P函数被成为down(减少信号量值)
down(struct semaphore *sem)获取信号量,不建议使用此函数,因为是 UNINTERRUPTABLE 的睡眠。
down_interruptible(struct semaphore *sem)可被中断地获取信号量,如果睡眠被信号中断,返回错误-EINTR。
down_trylock(struct semaphore *sem)尝试原子地获取信号量,如果成功获取,返回0,不能获取,返回1。
V函数是UP(增加信号量数值)
up(struct semaphore *sem)释放信号量sem。

一种特殊的信号量rwsem(读写信号量)
同一时刻最多有一个写者(writer)获得锁
同一时刻可以有多个读者(reader)获得锁
同一时刻写者和读者不能同时获得锁
<linux/rwsem.h>
初始化
init_rwsem(sem)
对只访问
down_read(struct rw_semaphore *sem);
down_read_trylock(struct rw_semaphore *sem)
up_read(struct rw_semaphore *sem)
针对写入者接口
down_write(struct rw_semaphore *sem)
down_write_trylock(struct rw_semaphore *sem)
up_write(struct rw_semaphore *sem)
downgrade_write(struct rw_semaphore *sem)

Completion机制
用于多线程之间的数据同步。类似于信号量,但是比信号量要安全。
<linux/completion.h>
创建1
DECLARE_COMPLETION(work)
创建2
void init_completion(struct completion *x)
等待
wait_for_completion(struct completion *);非中断的等待
触发
complete(struct completion *);唤醒一个
complete_all(struct completion *);唤醒全部

自旋锁(除了中断以外内部不允许休眠)
自旋锁是“原地等待”的方式解决资源冲突的。 
即,一个线程获取了一个自旋锁后,另外一个线程期望获取该自旋锁,获取不到,只能够原地“打转”(忙等待)。
自旋锁不会使线程状态发生切换
<linux/spinlock.h>
初始化1
spinlock_t lock;
spin_lock_init (&lock);
初始化2
DEFINE_SPINLOCK(lock);
取得自旋锁(上锁)
void spin_lock(spinlock_t *lock)
解锁
void spin_unlock(spinlock_t *lock)

读取者写入者自旋锁
<linux/rwlock.h>
<linux/rwlock_types.h>
初始化1
rwlock_t xxx_lock = __RW_LOCK_UNLOCKED(xxx_lock);
初始化2
rwlock_init(lock)
读取者
read_lock(lock)
read_lock_irqsave(lock, flags)
read_lock_irq(lock)
read_lock_bh(lock)

read_unlock(lock)
read_unlock_irqrestore(lock, flags)
read_unlock_irq(lock)
read_unlock_bh(lock)
写入者
write_lock(lock)
write_lock_irqsave(lock, flags)
write_lock_irq(lock)
write_lock_bh(lock)
write_trylock(lock)

write_unlock(lock)
write_unlock_irqrestore
write_unlock_irq(lock)
write_unlock_bh(lock)

循环缓冲区通用实现<linux/kfifo.k>

原子变量
整个操作的执行过程是原子的,不可中断的。
<asm/atomic.h>
atomic_t *v
初始化原子变量值1
atomic_set(v,i)
初始化原子变量值2
ATOMIC_INIT(i)
返回V的当前值
atomic_read(v)
将i的值累加到V
atomic_add(int i, atomic_t *v)
将i的值减少V
atomic_sub(int i, atomic_t *v)
累加1
atomic_inc(v)
减少1
atomic_dec(v)

原子位操作
<asm/bitops.h>
void set_bit(unsigned long nr, volatile unsigned long *addr)
void clear_bit(unsigned long nr, volatile unsigned long *addr) 
切换指定的原子位
void change_bit(unsigned long nr, volatile unsigned long *addr)
返回当前值
int test_bit(int nr, const volatile unsigned long *addr)

swqlock锁
读取者对资源自由访问
不能保护带指针的结构
<linux/seqlock.h>
seqlock_t
初始化1
SEQLOCK_UNLOCKED
初始化2
seqlock_init(x)
读取者
uint seq;
do{
    seq=read_seqbegin(&lock);
    ...
}while(read_seqretry(&lock,seq);
如果在中断处理版本中使用irq函数
read_seqbegin_irqsave(lock, flags)
read_seqretry_irqrestore
写入者
void write_seqlock(seqlock_t *sl)
void write_sequnlock(seqlock_t *sl)

RCU锁
<linux/rcupdate.h>
代码受RCU保护时必须在rcu_read_lock和rcu_read_unlock之间


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值