Chinaunix首页 | 论坛 | 博客
  • 博客访问: 319192
  • 博文数量: 163
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-23 17:54
个人简介

做一个“好”人... 思想上会思考; 生活上有追求; 技术上不停步; 工作上有担当;

文章分类

全部博文(163)

文章存档

2016年(1)

2015年(143)

2014年(19)

我的朋友

分类: LINUX

2014-12-23 21:36:33

主要的竞态发生在如下几种情况:
对称多处理器(SMP),
单CPU内进程抢占,
终端与进程之间。
上面只有SMP才是真正的并行,其他两种都是宏观并行,微观串行。

访问共享资源的代码区域称为临界区。临界区需要互斥机制加以保护。
中断屏蔽:
local_irq_disable();
...(临界区)
local_irq_enable()
它只能禁止和使能本CPU内的中断,并不能解决SMP引发的竞态。应该与自旋锁联合使用。
local_irq_save(flags)除了进行中断的操作外还保存目前CPU的中断位信息。local_irq_restore(flags)与之相反。
如果想禁止中断底半部,应使用local_bh_disable(),local_bh_enable().

原子操作:
整形原子变量操作:atomic_set(), atomic_read(), atomic_add()。。。。。。
位原子操作: set_bit(), clear_bit(), change_bit(), test_bit()
使用原子变量,使设备最多只能被一个进程打开。

自旋锁:
为了获得一个自旋锁,在某cpu上运行的代码要先执行一个原子操作,该操作测试并设置某个内存变量,由于它是原子操作,所以在该操作完成前其他执行单元不可能访问这个内存变量。如果测试表明锁空闲,则获得这个锁并继续操作;如果被占用,则重复这个测试,即“自旋”。
定义自旋锁:spinlock_t spin;
初始化:spin_lock_init(lock);
获得自旋锁:spin_lock(lock),如果能获得立即返回,否则自旋在那里; spin_trylock()尝试获得,无论结果如何都会立即返回,不在原地打转;
释放锁:spin_unlock()
使用方法:
spinlock_t lock;
spin_lock_init(&lock);
spin_lock (&lock);
...//临界区
spin_unlock(&lock);
在单内核且内核不支持抢占系统中,自旋锁退化为空操作。
自旋锁是忙等待,因此要在占用锁很短时使用。copy_from_user(), copy_to_user(), kmalloc()等函数可能引起阻塞,因此在自旋锁占用期间不能使用这些函数。

读写自旋锁rwlock:可以有多个读,但读和写之间不能同时。

顺序锁seqlock:可以读写同时进行。但被保护的共享资源不能含有指针,因为写执行单元可能使得指针失效,而读执行单元如果正要访问该指针将导致错误。
如果有写操作,读执行单元需要进行重读操作。模式如下:
do{
   seqnum = read_seqbegin(&seqlock_a);//读之前要使用该函数,它返回顺序锁的当前顺序号。
   ...
 }while (read_seqretry(&seqlock_a, seqnum));

读-拷贝-更新 RCU:
不需要锁,不使用原子指令。使用RCU写执行单元在访问它前要先复制一个副本,然后对副本进行修改,最后使用一个回调机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据,这个时机就是所有引用该数据的cpu都退出对共享数据的操作的时候。 它读写都能同步。 在写很多时开销较大。

信号量semaphore:与自旋锁类似,唯一不同的是当获取不到信号量时,进程不会原地打转,而是进入休眠等待状态。init_MUTEX()用于初始化一个用于互斥的信号量并将信号量设置为1。
down:获得信号量,但会导致睡眠,不能被信号打断,因此不能用于终端上下文。
down_interruptible()则睡眠可以被打断。
down_trylock()尝试获得信号量,如果能获得立刻返回0,否则返回非0.它不会导致睡眠,可以在中断上下文使用。
信号量使用:
DECLEAR_MUTEX(mount_sem);//定义和初始化信号量的快捷方式
down(&mount_sem);
...//临界区
up(&mount_sem);

完成量completion: 用于一个执行单元等待另一个执行单元执行完某事。
DECLEAR_COMPLETION(my_completion)定义和初始化的快捷方法。
wait_for_completion()等待一个completion被唤醒,
complete(), complete_all()唤醒完成。

自旋锁 VS 信号量
信号量是进程级的,用于多干进程间对资源的互斥。进程上下文切换开销大,因此只有当进程占用资源时间较长时,使用信号量才是好的选择。
当保护的临界区较短时,用自旋锁非常方便。
选用的3原则:
1,根据进程上下文切换时间和等待获取自旋锁的时间(由临界区执行时间决定)判断该使用何种。
2,信号量保护的临界区可以包含可能引起阻塞的代码,而自旋锁则不可以。因为阻塞意味着进程切换,如果进程被切换后另一个进程企图获得本自旋锁,会导致死锁。
3,信号量存在于进程上下文,因此如果被保护的共享资源需要在中断或软中断情况下使用,则在信号量与自旋锁之间只能选用自旋锁。

读写信号量rw_semaphore()

互斥体mutex
阅读(346) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~