内核中的锁
内核进程的竞争:
加锁:
等锁的三种方法:
1.如果没有锁,不等解锁直接返回
2.如果没有锁,就睡着等待解锁,当拿到锁之后,就会被唤醒,这种就是睡眠锁 ----》信号量 / 互斥体
3.如果没有锁,就一直要锁,这种最消耗cpu资源 ----》 自旋锁 ,举个例子:如果有两个人(进程),一个进门去喝水了,先把门锁住(加锁),喝着喝着,然后另一个人又敲门,他想进来喝水,但是现在门还没有解锁,然后他就一直敲门(消耗资源),直到等到另一个人出来(解锁)。
/arm_emb/sync_way :
同步的方法:
处于进程上下文的,自旋锁和互斥体和信号量都能用,加锁力度比较小,一般选用自旋锁。
注意:这里所说的加锁力度就是,举个例子假如说一个人进门喝水的时候,他一进门就把门锁住了 (加锁),然后自己以很短的时间就把水喝完了,而另一个人也想进来喝水,门还没开但是距离开门 (解锁) 的时间很短了,假如说他现在睡了,然后另外一个人又立马解锁了,这个时候他又要被唤醒,这就有点消耗资源,所以用自旋锁比较好,敲一会门,然后就开了
处于中断上下文的,必然选择用自旋锁,不能使用原子操作,如果给中断中加入
1.自旋锁: 非睡眠锁,中断上下文,必然是自旋锁,但是这个最消耗cpu资源
/******************************************/
进程和进程间的竞争
spinlock_t spin;
spin_lock_init(&spin);
//加锁
spin_lock(&spin);
//解锁
spin_unlock(&spin);
/*******************************************/
中断和进程的竞争
注意:cpsid i //汇编就是将 cpsr 寄存器的第 i 位置 1
spinlock_t spin;
//禁止中断并加锁
spin_lock_irqsave(&spin,cpsr);
//解锁并恢复中断
spin_unlock_irqrestore(&spin,cpsr);
/******************************************/
中断的下半部和进程之间的竞争
spinlock_t spin;
//禁止中断下半部并加锁
spin_lock_bh(&spin);
//解锁并恢复中断下半部
spin_unlock_bh(&spin);
/*******************************************/
2.互斥体: 睡眠锁,只允许锁的持有者只有一个
/******************************************/
进程和进程间的竞争
struct mutex mutex;
mutex_init(&mutex);
//加锁
mutex_lock(&mutex);
//解锁
mutex_unlock(&mutex);
/******************************************/
3.信号量: 睡眠锁,可以设置锁的持有者个数
/*******************************************/
进程和进程间的竞争
//实例化信号量的结构体
struct semaphore sema;
// @ val 锁的持有者的个数
static inline void sema_init(struct semaphore *sem, int val)
//加一操作
down();
//减一操作
up();
//尝试获得信号量,不等待
down_trylock();
/******************************************/
4.原子操作: 针对全局的整型的变量,比如在做 i++ 操作的时候,会出现竞争,这就需要原子操作
//v 是原子类型的全局变量
atomic_t v;
//如果返回 0 表示原子操作失败,
if (!atomic_dec_and_test(&v)) {
atomic_inc(&v); //
return -EBUSY;
}
atomic_inc(&mydev.v);
中断和进程的加锁解锁:
bne 1b //不相等的话,则跳转到此行以上的 1 标号那里去
ldrex 的这个 ex 表示内存独占
中断产生 GIC 不停的给 cpu 触发中断