案例 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 原子自增工程用法案例的更多相关文章

  1. Java Me-List控件的用法案例

    /** * Java Me-List控件的用法案例 */package com.xushouwei.cn; import java.io.IOException;import javax.microe ...

  2. Scala进阶之路-Scala中的枚举用法案例展示

    Scala进阶之路-Scala中的枚举用法案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的枚举值和Java中的枚举值有点差别,不过使用起来也都差大同小异,我这 ...

  3. Hadoop基础-MapReduce的Partitioner用法案例

    Hadoop基础-MapReduce的Partitioner用法案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Partitioner关键代码剖析 1>.返回的分区号 ...

  4. Hadoop基础-MapReduce的Combiner用法案例

    Hadoop基础-MapReduce的Combiner用法案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.编写年度最高气温统计 如上图说所示:有一个temp的文件,里面存放 ...

  5. jQuery中的ajax用法案例

    什么是 AJAX? AJAX = 异步 JavaScript 和 XML(Asynchronous JavaScript and XML). 简短地说,在不重载整个网页的情况下,AJAX 通过后台加载 ...

  6. gawk(awk)的用法案例

    gawk(awk)的用法案例 本文首先简单介绍一个gawk和awk的区别,然后是一点基本使用流程,最后是自己做的一个分析数据文件的脚本代码,供大家参考.另外想了解基本流程的入门知识的可以下载附件pdf ...

  7. Java8 新特性学习 Lambda表达式 和 Stream 用法案例

    Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...

  8. 快速入门GreenDao框架并实现增删改查案例

    大家的项目中不可避免的使用到SQLite,为此我们要花费心思编写一个增删改查框架.而一个好的ORM框架则能够给我们带来极大的方便,今天给大家讲解一个非常火热的ORM-GreenDao. 基本概念 Gr ...

  9. Java:多线程,java.util.concurrent.atomic包之AtomicInteger/AtomicLong用法

    1. 背景 java.util.concurrent.atomic这个包是非常实用,解决了我们以前自己写一个同步方法来实现类似于自增长字段的问题. 在Java语言中,增量操作符(++)不是原子的,也就 ...

随机推荐

  1. 利用shiro反序列化注入冰蝎内存马

    利用shiro反序列化注入冰蝎内存马 文章首发先知社区:https://xz.aliyun.com/t/10696 一.shiro反序列化注入内存马 1)tomcat filter内存马 先来看一个普 ...

  2. WEB文档在线预览解决方案

    web页面无法支持预览office文档,但是却可以预览PDF.flash文档,所以大多数解决方案都是在服务端将office文档转换为pdf,然后再通过js的pdf预览插件(谷歌浏览器等已经原生支持嵌入 ...

  3. RTD2171U替代方案|CS5266Typec转HDMI 4K60HZ转换芯片方案|CS5266芯片

    RTD2171U 是一款USB Type-C到HDMI转换器结合了USB Type-C输入接口和数字高清多媒体接口(HDMI)输出转换芯片.嵌入式微控制器基于工业标准8051内核.接收器端口将信道配置 ...

  4. Ubuntu复习笔记-认识Linux

    本次复习基于\(Ubuntu20.04\)的发行版进行总结,目的是更好记录自己学习的\(Linux\). 认识Linux 学习\(Linux\)之前,需要搞懂几个概念,\(Linux\)桌面操作系统与 ...

  5. 简单学生管理系统HTML前端页面

    效果图: 实现代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...

  6. 《MySQL数据操作与查询》- 维护学生信息、老师信息和成绩信息 支持按多种条件组合查询学生信息和成绩信息

    综合项目需求 一.系统整体功能 系统需支持以下功能: 维护学生信息.老师信息和成绩信息 支持按多种条件组合查询学生信息和成绩信息 学生 Student(id,班级id,学号,姓名,性别,电话,地址,出 ...

  7. 智慧巨鹿使用Rainbond落地实践,一个平台管理所有应用系统

    背景 大家好,我是北京数立通科技有限公司的李栋.最近几年,我一直负责"智慧巨鹿"这一智慧城市项目的运行与维护工作.这个项目涉及到10多家供应商开发的 30 多套智慧城市应用的运维管 ...

  8. SpringBoot集成MyBatis-Plus框架

    1.说明 本文介绍Spring Boot集成MyBatis-Plus框架, 重点介绍需要注意的地方, 是SpringBoot集成MyBatis-Plus框架详细方法 这篇文章的脱水版, 主要是三个步骤 ...

  9. 【Linux】Linux没有网络,可能的解决方法

    [root@localhost etc]# cd /etc/sysconfig/network-scripts/ [root@localhost network-scripts]# ll 修改此文件中 ...

  10. Hadoop开启Kerberos安全模式

    Hadoop开启Kerberos安全模式, 基于已经安装好的Hadoop的2.7.1环境, 在此基础上开启Kerberos安全模式. 1.安装规划 已经安装好Hadoop的环境 10.43.159.7 ...