并发与竞态及解决途径

来源:互联网 发布:多多返利网站源码 编辑:程序博客网 时间:2024/04/30 16:42
并发与竞态及解决途径
并发(concurrency)是指多个执行单元同时、并行的被执行,而并发执行单元对共享资源的访问很容导致竞态(racecondition)。
并发与竞态发生的条件:对称多处理器(SMP)的多个CPU;单CPU内进程与抢占它的进程;中断与进程之间。
解决并发与竞态的途径
访问共享资源的代码区域称为临界区域(criticalsection),解决竞态的根本途径就是对临界区的互斥访问,方法主要有中断屏蔽、原子操作、自旋锁、信号量、互斥体。
1、中断屏蔽
单CPU避免竞态的简单办法就是中断屏蔽,保证可以防止中断与进程间竞态条件的发生(所有中断被屏蔽后进程间切换的基础时钟中断也被屏蔽掉了)。
使用方法:
local_irq_disable()//禁止本地CPU的中断
......
critical section
......
local_irq_enable()
中断对保证系统正常运行非常重要,长时间屏蔽中断会让系统很危险。
2、原子操作
原子操作是指在执行过程中不会被别的代码路径所中断,可分为整形原子操作和位原子操作。
整形原子操作
atomic_t v;//定义原子变量v
void atomic_set(atomic_t *v, int i); //设置原子变量v的值为i
atomic_t v=ATOMIC_INT(0); //定义原子变量v,并初始化为0
atomic_read(atomic_t *v); //获取原子变量的值
void atomic_add(int i, atomic_t *v); //原子变量加i
void atomic_sub(int i, atomic_t *v); //原子变量减i
位原子操作
void set_bit(nr, void *addr); //设置addr指向的值的nr位为1
void clear_bit(nr, void *addr);
void change_bit(nr, void *addr); //第nr位取反
test_bit(nr, void *addr); //测试位
3、自旋锁

自旋锁主要针对SMP或单CPU且内核可抢占的情况,自旋锁可以保证临界区不受别的CPU和本CPU内的抢占进程打扰。当临界区可能受到中断和底半步影响时,应该使用自旋锁的衍生操作。

自旋锁是忙等待锁,当锁不可用时,CPU会不停地循环测试而不能做其它的工作,因此自旋锁会降低系统的性能。

如果临界区域发生阻塞,可能会导致死锁,因此在自旋锁占有期间内不能调用copy_from_user(),copy_to_user(), kmalloc()等函数

spinlock_t lock; //定义自旋锁

spin_lock_init(&lock);//初始化自旋锁

spin_lock(&lock);//获得自旋锁

spin_trylock(&lock);//尝试获得自旋锁

spin_unlock(&lock);//释放自旋锁

4、信号量

信号量和自旋锁不同的地方在于当进程得不到信号量时,进程会进入休眠或其它状态。

struct semaphore sem;//定义信号量

void sema_init(struct semaphore*sem, int val); //初始化信号量sem, 并把它的值设为val

DECLARE_MUTEX(name)//定义并初始化,相当于上面两句

DECLARE_MUTEX_LOCKED(name)//定义并初始化

void down(struct semaphore *sem);// 获得信号量,不能在中断上下文中使用,进入睡眠后不能用信号打断

int down_interruptible(structsemaphore *sem); //进入睡眠后可被信号打断

int down_trylock(struct semaphore*sem); //尝试获得信号量,不会睡眠,可以在中断上下文中使用

void up(struct semaphore *sem);//释放信号量

5、互斥体

互斥体完成的功能与信号量非常相识。

struct mutex my_mutex;//定义互斥体

mutex_init(&my_mutex); //初始化互斥体

void fastcall mutex_lock(structmutex *lock); //获取互斥体

int fastcallmut当ex_lock_interruptiable(structmutex *lock);

int fastcallmytex_trylock(struct mutex*lock);

void fastcallmutex_unlock(struct mutex*lock); //释放互斥体

自旋锁VS信号量

当临界区执行时间比较小时,采用自旋锁,否则采用信号量;

自旋锁绝对不能在临界区包含可能引起阻塞的代码,信号量可以;

如果临界区的代码在中断中执行,应该使用自旋锁或信号量的down_trylock()函数。
0 0
原创粉丝点击