Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1745532
  • 博文数量: 1493
  • 博客积分: 38
  • 博客等级: 民兵
  • 技术积分: 5834
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-19 17:28
文章分类

全部博文(1493)

文章存档

2016年(11)

2015年(38)

2014年(137)

2013年(253)

2012年(1054)

2011年(1)

分类: LINUX

2014-07-14 09:25:13

 

内核的几种锁同步机制

2014/6/10 冯健

1. atomic原子变量

typedef struct {

int counter;

} atomic_t;

可见,原子变量就是一个赤裸裸的整型,所以原子类型的变量只适用于对整形数据的原子操作。对它的读写都是采用了特殊的指令。

atomic_add(i, v)

atomic_dec(v)

atomic_inc(v)

atomic_sub(i, v)

atomic_set(v,i)

atomic_read(v)等等一系列的原子变量操作函数的实现,严重依赖于特殊指令。

armv5之前,特殊指令时swparmv6以后就是ldrex strex两个指令。简单的说,ldrex strex在加载、修改、写入内存变量counter内容时会锁住内存,或者说给内存加独占标记。这样就,可以保证了不存在多个CPU同时访问同一个原子变量。但是仅仅这样不能保证避免被同一个CPU上的中断打断啊?

引入ldrex strex后,只要在ldrexstrex之间对应的原子变量被修改,则strex失败。那么多核环境下,保证了多核间的互斥,同样的,如果单核上,atomic_add执行中产生了中断,影响了对应的v->counter,则atomic_add这次的原子加操作失败了,便重新来过。这样保证了操作的原子性。至于如何判断中断是否影响了对应的v->counter,有的是只要产生总线操作就视为影响,有的则在硬件上处理更为细致。

也就是,如果被中断了,那么这次原子变量操作会失败,可以通过返回值判断!!

而在armv5之前的单核arm架构中,上述原子操作函数是通过raw_local_irq_save来实现的,这样仅仅关闭了本地的中断,因为对原子变量操作的打断只会来自于中断。虽然还可能来自内核抢占,但是,研究之后知道,内核抢占只会发生在中断程序返回内核空间,以及内核线程主动放弃执行的情况下。关闭了本地中断,也就断了内核抢占的来源!!

当然了,现在的情况是,几乎只需要考虑ldrex strex了,arm已经普遍使用到了armv6版本以上。

2. spin_lock自旋锁

自旋锁是一个大而全的锁同步方案!为什么这么说?因为任何想用到锁同步的地方都可以使用它,中断代码中、普通内核代码中都可以,只是开销的问题而已,spin_lock原则是要快而迅速的完成!且临界区内最好不要使用可能引起睡眠的函数,试想,你获取了锁却去睡觉了,若有个人想得到锁,他永远也没办法得到!使用原则可以参见《linux设备驱动归纳总结(四):5.SMP下的竞态和并发》

在单CPU非抢占内核中,spin_lock_irqsave是空操作。

在单CPU抢占内核中,spin_lock_irqsavepreempt_disable关内核抢占、以及关中断操作。

在多CPU非抢占内核中,spin_lock_irqsave是关本地中断、以及通过atomic操作实现CPU间互锁。

在单CPU抢占内核中,spin_lock_irqsave是关本地中断、preempt_disable关内核抢占、以及通过atomic操作实现CPU间互锁。

我看了源码,在多CPU架构的spin_lock的实现中,我看见了atomic操作的身影,不知道spin_lock_irqsave是不是真的是以atomic为基础来实现的?

3. 信号量/互斥量

struct semaphore {

atomic_t count;

int sleepers;

wait_queue_head_t wait;

};

struct semaphore sem

sema_init(&sem, count)

#define init_MUTEX(sem) sema_init(sem, 1)

可以发现,信号量居然也是使用原子变量作为基本类型,只不过加了一个睡觉进程队列头。信号量显然用于可以睡眠的环境下,那就是说信号量使用的主体应该是进程上下文(系统调用)以及内核线程。中断上下文,显然绝对不可以使用(其实也可以,只要不引起睡眠)!

另外,一般使用的是二元的信号量,也就是互斥量。

4. RCU read-copy-update

可以参见深入linux内核架构5.2章节。一种类似于读写锁的机制。

5. 内存屏障

参见 《内存屏障 》  

阅读(992) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~