惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
J
Java Code Geeks
Blog — PlanetScale
Blog — PlanetScale
F
Fortinet All Blogs
腾讯CDC
大猫的无限游戏
大猫的无限游戏
Jina AI
Jina AI
WordPress大学
WordPress大学
雷峰网
雷峰网
小众软件
小众软件
D
DataBreaches.Net
V
Visual Studio Blog
博客园 - Franky
IT之家
IT之家
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog RSS Feed
博客园 - 聂微东
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
云风的 BLOG
云风的 BLOG

土法炼钢兴趣小组的算法知识备份

国密算法与国密 TLS 系列索引 【系统架构设计】架构质量属性:不只是"高可用高性能" 【系统架构设计百科】告警策略:如何避免"狼来了" 【系统架构设计】CQRS:读写分离的架构哲学 【系统架构设计】空间架构:极端扩展场景的解法 【系统架构设计】微服务架构深度审视:优势、代价与适用边界 【系统架构设计】扩展性原理:水平、垂直与对角扩展 【系统架构设计】无状态设计:扩展的第一步也是最难的一步 【系统架构设计】缓存架构:从本地到分布式的多级缓存体系 【系统架构设计】管道与过滤器:Unix 哲学的架构表达 【系统架构设计】复杂性管理:架构的核心战场 【系统架构设计】消息队列架构:异步解耦的设计与陷阱 【系统架构设计】CDN 架构:全球加速的设计原理 【系统架构设计】连接池设计:被忽视的性能杀手 【系统架构设计】弹性设计模式:熔断器、舱壁与超时 【系统架构设计】高可用设计模式:冗余、故障转移与仲裁 【系统架构设计】容量规划:从拍脑袋到数据驱动 【系统架构设计】数据库扩展:分库分表的工程实践与替代方案 【系统架构设计】SLO 工程:可靠性的量化管理 【系统架构设计】性能建模:用数学思维分析系统瓶颈 【系统架构设计】混沌工程:主动验证系统的韧性 【系统架构设计】零拷贝与内存映射:数据搬运的极致优化 【系统架构设计】线程模型:从 thread-per-request 到协程 【系统架构设计】容灾架构:多活与灾备设计 【系统架构设计】数据库性能模式:索引、查询与连接管理 【系统架构设计】数据建模:从关系范式到文档模型的真实权衡 【系统架构设计】吞吐量优化:批处理、流水线与并发模型 【系统架构设计】流处理架构:从批处理到实时的范式迁移 【系统架构设计】搜索引擎架构:倒排索引之上的系统设计 【系统架构设计】时序数据架构:监控与 IoT 的存储设计
【操作系统百科】原子 RMW 操作
2026-05-25 · via 土法炼钢兴趣小组的算法知识备份

atomic_inc(&counter) 背后,不同 CPU 架构的实现天差地别。理解硬件原子原语,才能写出高性能并发代码。

一、先看图

flowchart LR
    subgraph x86
        LOCK[LOCK prefix<br/>锁总线/缓存行] --> MESI[MESI 协议<br/>保证一致性]
    end
    subgraph ARMv8_early["ARM LL/SC"]
        LDXR[LDXR 加载独占] --> STXR[STXR 存储独占<br/>可能失败 → 重试]
    end
    subgraph ARMv8_1["ARM LSE"]
        LSE_ADD[LDADD<br/>硬件原子加]
    end
    subgraph RISCV["RISC-V A"]
        AMO[AMOADD<br/>原子加]
        LR_SC[LR/SC<br/>类似 LL/SC]
    end
    classDef x86c fill:#388bfd22,stroke:#388bfd,color:#adbac7;
    classDef armc fill:#3fb95022,stroke:#3fb950,color:#adbac7;
    classDef rvc fill:#a371f722,stroke:#a371f7,color:#adbac7;
    class LOCK,MESI x86c
    class LDXR,STXR,LSE_ADD armc
    class AMO,LR_SC rvc

二、x86:LOCK 前缀

lock add [counter], 1     ; 原子加
lock cmpxchg [ptr], rax   ; CAS
lock xadd [counter], rax  ; fetch_add

LOCK 前缀让 CPU 独占缓存行 → MESI E/M 状态 → 其他核的读必须等。

成本:

  • 同一缓存行无竞争 → ~10-20 cycles
  • 竞争激烈 → 100+ cycles(cache line bouncing)

三、ARM LL/SC

retry:
    ldxr  x0, [x1]       // Load-Exclusive
    add   x0, x0, #1
    stxr  w2, x0, [x1]   // Store-Exclusive
    cbnz  w2, retry       // 失败则重试

独占监视器(exclusive monitor)跟踪 cacheline。其他核写同一行 → stxr 失败 → 重试。

问题:高竞争 → 无限重试(livelock 风险)。

四、ARMv8.1 LSE

大型原子扩展(Large System Extensions):

ldadd  x0, x1, [x2]    // 硬件原子 fetch_add
cas    x0, x1, [x2]    // 硬件 CAS
swp    x0, x1, [x2]    // 硬件 swap

硬件保证原子性,无重试循环。

性能:64 核以上 → LSE 比 LL/SC 快 10 倍以上。

内核检测 LSE → 运行时选择 LL/SC 或 LSE 路径(ALTERNATIVE 宏)。

五、RISC-V A 扩展

两种方式并存:

amoadd.w  a0, a1, (a2)   // 原子加
lr.w      a0, (a1)        // Load-Reserved
sc.w      a2, a0, (a1)    // Store-Conditional

类似 ARM 的两代方案。

六、内核 atomic API

atomic_t counter = ATOMIC_INIT(0);
atomic_inc(&counter);                          // ++
atomic_dec_and_test(&counter);                 // --,返回是否为 0
int old = atomic_fetch_add(5, &counter);       // fetch_add
bool ok = atomic_try_cmpxchg(&counter, &old, new);  // CAS

底层展开为架构对应的原子指令。

七、Cache Line Bouncing

sequenceDiagram
    participant C0 as Core 0
    participant C1 as Core 1
    participant CL as Cache Line

    C0->>CL: atomic_inc → 获取 E 状态
    C1->>CL: atomic_inc → 发送 Invalidate
    C0->>CL: 降级到 I 状态
    C1->>CL: 获取 E 状态 → 执行
    C0->>CL: 再次 atomic_inc → 又要抢

高频原子操作在同一 cacheline → 核间不断争抢 → 性能崩溃。

解决:per-CPU 计数 → 只在需要精确值时汇总。

八、Tearing

非原子宽度访问可能被拆成多次总线事务:

long x;  // 64 位
// 32 位 CPU 上,读/写可能拆成两个 32 位操作 → tearing

内核保证:atomic_long_tREAD_ONCE/WRITE_ONCE 在对齐地址上原子。

九、CAS vs fetch_add

操作 失败重试 竞争时性能 用途
CAS 需要(compare-and-swap) 高竞争退化 通用
fetch_add 无需重试 稳定 计数器、序列号

尽可能用 fetch_add 替代 CAS loop。

十、小结

  • x86 LOCK 前缀简单高效但竞争时代价高
  • ARM LL/SC 灵活但高竞争可能 livelock
  • ARM LSE / RISC-V AMO 提供硬件原子操作
  • cache line bouncing 是并发性能的头号杀手
  • 内核 atomic API 封装了架构差异

参考文献

  • arch/x86/include/asm/atomic.h
  • arch/arm64/include/asm/atomic_lse.h
  • Documentation/atomic_t.txt
  • linux/cas-vs-helping(旧文延伸阅读)
  • Will Deacon, “ARM64 atomics and LSE.” 2018

工具

  • perf stat -e cache-misses
  • perf c2c(cache line false sharing 检测)
  • objdump -d(查看原子指令生成)

延伸阅读


上一篇Linux 内核内存模型 下一篇spinlock 家族

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-27 · os

【操作系统百科】内存回收

Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。

2026-04-28 · os

【操作系统百科】交换

swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。

2026-05-03 · os

【操作系统百科】Slab/SLUB 分配器

buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。

2026-05-07 · os

【操作系统百科】用户态分配器

glibc malloc、tcmalloc、jemalloc、mimalloc 各有哲学。本文讲 arena、thread cache、size class、madvise 返还策略、碎片与 RSS 膨胀、如何根据负载选分配器。