多线程(12)atomic 原子操作系列接口
- 1. 原子操作
- 2. 使用场景
- 3. 接口
- 4. 例子
- 5. 扩展:atomic_add_unless
- 参考
1. 原子操作
所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断。也就说,它是最小的执行单位,不可能有比它更小的执行单位,因此这里的原子实际是使用了物理学里的物质微粒的概念。
总结就是: 不可中断的操作。
1.1 atomic_t 源码定义
linux专门定义了一种只进行原子操作的类型atomic_t
typedef struct { volatile int counter;
} atomic_t;
原子变量作用:
主要是防止读取的是寄存器的内容,而内存的值已经被其他线程改变,主要是因为多线程的原因
本质: 原子类型其实是int类型,只是禁止寄存器对其暂存。
volatile 关键字
https://mp.csdn.net/mp_blog/creation/success/105363581
2. 使用场景
原子操作主要用于实现资源计数
很多引用计数(refcnt)就是通过原子操作实现的。
3. 接口
atomic_read(atomic_t * v); //原子读操作,它返回原子类型的变量v的值
atomic_set(atomic_t * v, int i);//设置原子类型的变量v的值为i
void atomic_add(int i, atomic_t *v); //给原子类型的变量v增加值i
atomic_sub(int i, atomic_t *v); //从原子类型的变量v中减去i。
int atomic_sub_and_test(int i, atomic_t *v); //从原子类型的变量v中减去i,并判断结果是否为0,如果为0,返回真,否则返回假。
void atomic_inc(atomic_t *v); //对原子类型变量v原子地增加1。
void atomic_dec(atomic_t *v); //对原子类型的变量v原子地减1。
int atomic_add_negative(int i, atomic_t *v);//对原子类型的变量v原子地增加I,并判断结果是否为负数,如果是,返回真,否则返回假。
int atomic_add_return(int i, atomic_t *v);//对原子类型的变量v原子地增加i,并且返回指向v的指针。
int atomic_sub_return(int i, atomic_t *v);//从原子类型的变量v中减去i,并且返回指向v的指针。
int atomic_inc_return(atomic_t * v);//对原子类型的变量v原子地增加1并且返回指向v的指针。
int atomic_dec_return(atomic_t * v);//对原子类型的变量v原子地减1并且返回指向v的指针。
4. 例子
atomic_t stCount;
atomic_set(&(stCount), 0); /* 初始化 */
atomic_inc(&(stCount));/* 累加 */
unsigned int iRet = (unsigned int)atomic_read(&(stCount)); /* 读取 */
5. 扩展:atomic_add_unless
int atomic_add_unless(atomic_t *v, int a, int u)
功能:
如果 v!=u 则 v+=a 返回非0 如果 v=u 则 不处理v 返回0
参数说明
v:原子类型变量指针。关于原子类型atomic_t的定义参考atomic_set()函数的分析。a:整型值,在v的值不为u时,原子类型变量的值将在其原有基础上增加该变量值。u:整型值,被用来与v的值进行比较来决定是否对v进行增加a。
返回值:
返回一个整型值,如果起初原子类型v的值即与u相等,则返回0,否则返回非0值。
例子:
(VOID)atomic_add_unless(&pstStatHashNode->stActiveConnections, -1, 0);
就是 stActiveConnections-1
源码实现:
static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
{ int ret; unsigned long flags; raw_local_irq_save(flags); ret = v->counter; if (likely(ret == old)) v->counter = new; raw_local_irq_restore(flags); return ret;
}static inline int atomic_add_unless(atomic_t *v, int a, int u)
{ int c, old; c = atomic_read(v); while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c) c = old; return c != u;
}
参考
https://www.cnblogs.com/still-smile/p/11652788.html
https://www.cnblogs.com/wanghuaijun/p/7705045.html