Linux 驱动中实现并发控制,由此产生了并发控制的技术。
这些技术包括: 原子操作、自旋锁、RCU、信号量、互斥体和完成量。
主要的并发控制技术
- 原子操作
- 自旋锁(Spin lock)
- 读-复制-更新(RCU)机制
- 信号量(Semaphore)
- 互斥体(Mutex)
- 完成量(Completion)
原子操作:
原子操作指的是在执行过程中不会被别的代码路径所中断的操作。
或者 “可被中断的一个或一系列操作”
原子操作分为两类:整型原子操作、位原子操作
2.1 整型原子操作:
设置原子变量的值:
void atomic_set(atomic_t *v, int i); /* 设置原子变量的值为 i */
atomic_t v = ATOMIC_INIT(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 atomic_inc(atomic_t *v); /* 自加1 */
void atomic_dec(atomic_t *v); /* 自减1 */
操作并测试:
int atomic_inc_and_test(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
int atomic_sub_and_test(int i, atomic_t *v);
对原子变量执行自增、自减和减操作后(无加)测试其是否为 0,
0,true
!0,false
操作并返回:
int atomic_add_return(int i, atomic_t *v);
int atomic_sub_return(int i, atomic_t *v);
int atomic_inc_return(atomic_t *v);
int atomic_dec_return(atomic_t *v);
执行完操作后,返回新的值
2.2 位原子操作:
置位: -- 置1
void set_bit(nr, void *addr);
功能:
将 addr 地址的第 nr 位置为 1
清零:
void clear_bit(nr, void *addr);
位翻转:
void change_bit(nr, void *addr);
测试:
test_bit(nr, void *addr);
功能:
返回 addr 位的第 nr 位
测试并操作:
int test_and_set_bit(nr, void *addr);
int test_and_clear_bit(nr, void *addr);
int test_and_change_bit(nr, void *addr);
功能:
相当于先执行了test_bit(nr, void *addr)后再执行 xxx_bit(nr, void *addr)
3. 原子操作的实例:
实现 设备最多只能被一个进程打开:
关键的函数:
atomic_t v = ATOMIC_INIT(1);
static int hello_open (struct inode *inode, struct file *file)
{
if (!atomic_dec_and_test(&v))
{
atomic_inc(&v);
return -EBUSY;
}
printk (KERN_INFO "Hey! device opened\n");
return 0;
}
static int hello_release (struct inode *inode, struct file *file)
{
atomic_inc(&v);
printk (KERN_INFO "Hmmm! device closed\n");
return 0;
}
函数说明:(hello_open函数)
①第一次打开设备驱动的时候 v = 1,v - 1 = 0 ,atomic_dec_and_test(&v) 结果是 true,不进循环,不返回EBUSY,执行下边内容。
②第二次打开设备驱动,v = 0, v - 1 = -1,atomic_dec_and_test(&v) 结果是 false,进循环,直接返回。