案例 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. 当MySQL执行XA事务时遭遇崩溃,且看华为云如何保障数据一致性

    摘要:当前MySQL所有版本不支持分布式事务的崩溃恢复安全,这严重影响了分布式事务的高可用保障. 华为云数据库内核高级技术专家,拥有十多年MySQL内核研发经验,目前在华为云数据库团队研发华为云数据库 ...

  2. playwright--自动化(一):快速上手

    Playwright为现代 Web 应用程序提供可靠的端到端测试. 在JavaScript 和 TypeScript.Python..NET和Java 中都可以使用 Playwright 本人选择py ...

  3. 新环境chart包helmlint校验

    在iot目录内可以执行helm lint iot-api 去校验

  4. Log4j2基本使用入门

    1.Log4j2简介 Apache Log4j 2是日志框架Log4j的升级, 它比其前身Log4j 1.x提供了重要的改进, 并且参考了Logback中许多有用的改进, 同时修复了Logback的一 ...

  5. 【】Elasticsearch客户端API使用Demo

    Elasticsearch客户端API使用Demo, 转载自官方文档, 以索引雇员文档为示例, 在命令行使用curl演示了一系列的Restful API操作. 1.索引雇员文档 第一个业务需求就是存储 ...

  6. Location配置项及LNMP架构

    目录 Location配置项及LNMP架构 Location location匹配符号 LNMP架构 UWSGI uwsgi服务部署 部署BBS项目 步骤 Location配置项及LNMP架构 Loc ...

  7. Pytest_fixture(9)

    什么是fixture fixture是pytest特有的功能,使用装饰器 @pytest.fixture 标记的函数在其他函数中能被当作参数传入并被调用. fixture有明确的名字,在其他函数,模块 ...

  8. 初识python: 自定义函数

    什么是函数? 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.函数能提高应用的模块性,和代码的重复利用率. 函数的定义方法: def test(x): '函数定义方法' x+=1 r ...

  9. 在quasar 注册全局filter

    A common use case for Quasar applications is to run code before the root Vue app instance is instant ...

  10. Linux上天之路(十七)之Shell编程二

    一.shell常用工具 grep 1.作用 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Exp ...