Linux驱动(并发):04---原子操作(atomic_t、atomic_set、set_bit)

一、原子操作介绍

  • 原子操作可以保证对一个整型数据的修改是排他性的
  • Linux内核提供了一系列函数来实现内核中的 原子操作,这些函数又分为两类,分别针对位和整型变量进行原子操作
  • 位和整型变量的原子操作都依赖于底层CPU的原子操作,因此所有这些函数都与CPU架构密切相关
  • 对于ARM处理器而言,底层使用 LDREX和STREX指令,比如atomic_inc()底层的实现会调用到atomic_add(),其代码如下:
static inline void atomic_add(int i, atomic_t *v)
{
    unsigned long tmp;
    int result;
    prefetchw(&v->counter);
    __asm__ __volatile__("@ atomic_add\n"
"1: ldrex %0, [%3]\n"
"   add %0, %0, %4\n"
"   strex %1, %0, [%3]\n"
"   teq %1, #0\n"
"   bne 1b"
    : "=&r" (result),"=&r" (tmp),"+Qo" (v->counter)
    : "r" (&v->counter),"Ir" (i)
    : "cc");
}

二、整型原子操作

设置原子变量的值

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 */

操作并测试

  • 下述操作对原子变量执行自增、自减和减操作后(注意没有加),测试其是否为0,为0返回true,否 则返回false
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);

 操作并返回

  • 下述操作对原子变量进行加/减和自增/自减操作,并返回新的值
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);

三、位原子操作

设置位

  • 下述操作设置addr地址的第nr位,所谓设置位即是将位写为1
void set_bit(nr, void *addr);

清除位

  • 下述操作清除addr地址的第nr位,所谓清除位即是将位写为0
void clear_bit(nr, void *addr);

改变位

  • 下述操作对addr地址的第nr位进行反置
void change_bit(nr, void *addr);

测试位

  • 下述操作返回addr地址的第nr位
test_bit(nr, void *addr);

测试并操作位

  • 下述test_and_xxx_bit(nr,void*addr)操作等同于执行test_bit(nr,void*addr)后再执行 xxx_bit(nr,void*addr)
int test_and_set_bit(nr, void *addr);
int test_and_clear_bit(nr, void *addr);
int test_and_change_bit(nr, void *addr);

四、演示案例

  • 下面给出了原子变量的使用例子,它使得设备最多只能被一个进程打开
static atomic_t xxx_available = ATOMIC_INIT(1); /* 定义原子变量*/

static int xxx_open(struct inode *inode, struct file *filp)
{
    ...
    if (!atomic_dec_and_test(&xxx_available)) {
        atomic_inc(&xxx_available);
        return - EBUSY; /* 已经打开*/
    }
    ...
    return 0; /* 成功 */
}

static int xxx_release(struct inode *inode, struct file *filp)
{
    atomic_inc(&xxx_available); /* 释放设备 */
    return 0;
}

 

你可能感兴趣的:(Linux驱动(并发))