原子变量的操作是一种不可以被打断的操作,原子操作需要硬件支持,因此是架构相关。
类似于汇编的一条汇编指令,不可以被分割。
两种原子变量:
有时候需要共享的资源可能只是一个简单的整型数值。例如在驱动程序中,需要对包含一个count的计数器。这个计数器表示有多少个应用程序打开了设备所对应的设备文件。
通常在设备驱动程序的open()函数中,将count变量加1,在close)函数中,将count减1。如果只有一个应用程序执行打开和关闭操作,那么这里的count计数不会出现问题。但是如果有多个应用程序同时打开或者关闭设备文件,那么就可能导致count多加或者少加,出现错误。为了避免这个问题,内核提供了一个原子整型变量,称为atomict。该变量的定义如下:
typedef struct {
int counter;
} atomic_t;
不能直接对该结构体变量操作,内核中有专门的函数:
#define ATOMIC_INIT(i) { (i) }
如:atomic_t cout = ATOMIC_INIT(1);
#define atomic_set(v,i) (((v)->counter) = (i))
#define atomic_read(v) (*(volatile int *)&(v)->counter)
static inline void atomic_add(int i, atomic_t *v)
static inline void atomic_sub(int i, atomic_t *v)
#define atomic_inc(v) atomic_add(1, v)
#define atomic_dec(v) atomic_sub(1, v)
#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) //自加测试
#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) //自加测试
#define atomic_inc_return(v) (atomic_add_return(1, v)) //返回值
#define atomic_dec_return(v) (atomic_sub_return(1, v))
#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) //减I测试
除了原子整数操作外,还有原子位操作。原子位操作是根据数据的每一位单独进行操作。根据体系结构的不同,原子位操作函数的实现也不同。这些函数的原型如下代码所示。
static inline void set_bit(int nr, volatile unsigned long *addr)
static inline void clear_bit(int nr, volatile unsigned long *addr)
static inline void change_bit(int nr, volatile unsigned long *addr)
static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
需要注意的是,原子位操作和原子整数操作是不同的。原子位操作不需要专门定义一个类似atomic-t类型的变量,只需要一个普通的变量指针就可以了。下面对上面的几个函数进行简要的分析:
第01行, set bit()函数将addr变量的第nr位设置为1
第02行, clearbit()函数将addr变量的第nr位设置为0
第03行, change bit()函数将addr变量的第nr位设置为相反的数。
第04行, test and-set bit()函数将addr变量的第nr位设置为1,并返回没有修改之前的值。
第05行, test and-clear-bit()函数将addr变量的第nr位设置为0,并返回没有修改之前的值。
第06行, test and-change-bit()函数将addr变量的第nr位设置为相反的数,并返回没有修改之前的值。
https://blog.csdn.net/qq_40732350/article/details/83045200