atomic 原子自增工程用法案例
案例 1 : 简单用法
atomic_int id;
atomic_fetch_add(&id, 1)
atomic_uint id;
atomic_fetch_add(&id, 1)
上面两种原子自增简单用法. 这里面有潜在问题. 例如第一段代码中 atomic_fetch_add(&id, 1) 这种 id++
加到最后会溢出需要看业务能否接受了. 第二种死板一点, 也是一样看业务取舍, 例如杂糅一些特殊业务值非常困难.
案例2: skynet 项目中 socket id 设计
https://github.com/cloudwu/skynet/blob/master/skynet-src/socket_server.c#L345-L371
static int
reserve_id(struct socket_server *ss) {
int i;
for (i=0;i<MAX_SOCKET;i++) {
int id = ATOM_FINC(&(ss->alloc_id))+1;
if (id < 0) {
id = ATOM_FAND(&(ss->alloc_id), 0x7fffffff) & 0x7fffffff;
}
struct socket *s = &ss->slot[HASH_ID(id)];
int type_invalid = ATOM_LOAD(&s->type);
if (type_invalid == SOCKET_TYPE_INVALID) {
if (ATOM_CAS(&s->type, type_invalid, SOCKET_TYPE_RESERVE)) {
s->id = id;
s->protocol = PROTOCOL_UNKNOWN;
// socket_server_udp_connect may inc s->udpconncting directly (from other thread, before new_fd),
// so reset it to 0 here rather than in new_fd.
ATOM_INIT(&s->udpconnecting, 0);
s->fd = -1;
return id;
} else {
// retry
--i;
}
}
}
return -1;
}
其中 ATOM_FINC, ATOM_FAND 设计如下
https://github.com/cloudwu/skynet/blob/master/skynet-src/atomic.h
#else #include <stdatomic.h> #define ATOM_INT atomic_int
#define ATOM_POINTER atomic_uintptr_t
#define ATOM_SIZET atomic_size_t
#define ATOM_ULONG atomic_ulong
#define ATOM_INIT(ref, v) atomic_init(ref, v)
#define ATOM_LOAD(ptr) atomic_load(ptr)
#define ATOM_STORE(ptr, v) atomic_store(ptr, v)
#define ATOM_CAS(ptr, oval, nval) atomic_compare_exchange_weak(ptr, &(oval), nval)
#define ATOM_CAS_POINTER(ptr, oval, nval) atomic_compare_exchange_weak(ptr, &(oval), nval)
#define ATOM_FINC(ptr) atomic_fetch_add(ptr, 1)
#define ATOM_FDEC(ptr) atomic_fetch_sub(ptr, 1)
#define ATOM_FADD(ptr,n) atomic_fetch_add(ptr, n)
#define ATOM_FSUB(ptr,n) atomic_fetch_sub(ptr, n)
#define ATOM_FAND(ptr,n) atomic_fetch_and(ptr, n) #endif
他的思路是, 通过 atomic_fetch_and 来避免 atomic_fetch_add 溢出问题. 但也存在一个问题, 就是 atomic_fetch_and 存在返回相同值情况,
所以返回的 id 会重复. 这里他借助 atomic_compare_exchange_weak + 业务判断 让重复 id 再次重试.
案例3: structc 中 id 设计
https://github.com/wangzhione/structc/blob/master/modular/test/timer.c.h#L28-L56
// timer_list 链表对象管理器
struct timer_list {
atomic_int id; // 当前 timer node id
atomic_flag lock; // 自旋锁
volatile bool status; // true is thread loop, false is stop
struct timer_node * list; // timer list list
}; // 定时器管理单例对象
static struct timer_list timer = { .id = 1, .lock = ATOMIC_FLAG_INIT }; // get atomic int 1 -> INT_MAX -> 1
static inline int timer_list_id() {
// 0 -> INT_MAX -> INT_MIN -> 0
int id = atomic_fetch_add(&timer.id, 1) + 1;
if (id < 0) {
// INT_MAX + 1 -> INT_MIN
// 0x7F FF FF FF + 1 -> 0x80 00 00 00 // INT_MIN & INT_MAX => 0x80 00 00 00 & 0x7F FF FF FF => 0x00 00 00 00
// id = atomic_fetch_and(&timer.id, INT_MAX) & INT_MAX;
// Multiple operations atomic_fetch_and can ensure timer.id >= 0
atomic_fetch_and(&timer.id, INT_MAX); // again can ensure id >= 1
id = atomic_fetch_add(&timer.id, 1) + 1;
}
return id;
}
这个设计把 id 分为三段, -1, 0, 还有 > 0 . timer_list_id 函数返回 >= 1 id. 这里利用二次 atomic_fetch_add 原子自增同时继续保持不重复性.
后记:
技巧是为想法和需求服务, 欢迎补充更多原子操作用法.

atomic 原子自增工程用法案例的更多相关文章
- Java Me-List控件的用法案例
/** * Java Me-List控件的用法案例 */package com.xushouwei.cn; import java.io.IOException;import javax.microe ...
- Scala进阶之路-Scala中的枚举用法案例展示
Scala进阶之路-Scala中的枚举用法案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的枚举值和Java中的枚举值有点差别,不过使用起来也都差大同小异,我这 ...
- Hadoop基础-MapReduce的Partitioner用法案例
Hadoop基础-MapReduce的Partitioner用法案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Partitioner关键代码剖析 1>.返回的分区号 ...
- Hadoop基础-MapReduce的Combiner用法案例
Hadoop基础-MapReduce的Combiner用法案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.编写年度最高气温统计 如上图说所示:有一个temp的文件,里面存放 ...
- jQuery中的ajax用法案例
什么是 AJAX? AJAX = 异步 JavaScript 和 XML(Asynchronous JavaScript and XML). 简短地说,在不重载整个网页的情况下,AJAX 通过后台加载 ...
- gawk(awk)的用法案例
gawk(awk)的用法案例 本文首先简单介绍一个gawk和awk的区别,然后是一点基本使用流程,最后是自己做的一个分析数据文件的脚本代码,供大家参考.另外想了解基本流程的入门知识的可以下载附件pdf ...
- Java8 新特性学习 Lambda表达式 和 Stream 用法案例
Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...
- 快速入门GreenDao框架并实现增删改查案例
大家的项目中不可避免的使用到SQLite,为此我们要花费心思编写一个增删改查框架.而一个好的ORM框架则能够给我们带来极大的方便,今天给大家讲解一个非常火热的ORM-GreenDao. 基本概念 Gr ...
- Java:多线程,java.util.concurrent.atomic包之AtomicInteger/AtomicLong用法
1. 背景 java.util.concurrent.atomic这个包是非常实用,解决了我们以前自己写一个同步方法来实现类似于自增长字段的问题. 在Java语言中,增量操作符(++)不是原子的,也就 ...
随机推荐
- misc之压缩文件处理
misc之压缩文件处理 一.预备知识 1.头文件名代码 二.实验环境 1.winhex 三.题目来源 攻防世界杂项:János-the-Ripper.再见李华 实验一 打开题目文件是一个压 ...
- 【死磕Java并发】-----Java内存模型之重排序
在执行程序时,为了提供性能,处理器和编译器常常会对指令进行重排序,但是不能随意重排序,不是你想怎么排序就怎么排序,它需要满足以下两个条件: 在单线程环境下不能改变程序运行的结果: 存在数据依赖关系的不 ...
- 第三十七个知识点: The Number Field Sieve
第三十七个知识点: The Number Field Sieve 数域筛法(The Number Field Sieve ,NFS)是已知的分解算法中最有效率的.它的运行时间取决于被分解的数的大小而不 ...
- SRGAN
目录 概 主要内容 代码 Ledig C., Theis L., Huszar F., Caballero J., Cunningham A., Acosta A., Aitken A., Tejan ...
- Gradient-based Hyperparameter Optimization through Reversible Learning
目录 概 主要内容 算法 finite precision arithmic 实验 Maclaurin D, Duvenaud D, Adams R P, et al. Gradient-based ...
- JWT+SpringBoot实战
往期内容:JWT - 炒焖煎糖板栗 - 博客园 (cnblogs.com) JWT可以理解为一个加密的字符串,里面由三部分组成:头部(Header).负载(Payload).签名(signature) ...
- Java初学者作业——用户输入一个小数,程序分解出整数部分和小数部分。
返回本章节 返回作业目录 需求说明: 用户输入一个小数,程序分解出整数部分和小数部分. 实现思路: 接收用户控制台输入的小数. 用强制类型转换将整数部分得到. 使用用户输入的小数减去整数部分得到小数部 ...
- pytest执行用例:明明只写了5个测试用例, 怎么收集到33个!?
pytest收集测试用例的顺序: 同一个项目中搜索所有以test_开头的测试文件.test_开头的测试类.test_开头的测试函数 执行测试用例的顺序: 是按照先数据(0~9)>再字母(a~z) ...
- Linux如何对文件内容中的关键字进行查找
如果是用vi打开文件后,在命令行下输入"/关键字"如果是在没有打开文件的前提就用"cat 文件名 | grep "关键字"
- 方法覆盖 和toString方法的作用
当我们代码怎么编写的时候,在代码级别上构成了方法的覆盖呢? 两个类必须要有继承关系. 重写之后的方法和之前的方法具有:相同的返回值类型 相同的方法名 相同的形参列表 访问权限不能更高,只能更低 重写之 ...