You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中该原子引用计数优化实现是否安全?

代码安全性分析:跨线程引用计数实现

给定前提条件

  • Header_mark_as_shared仅在对象跨线程前调用,无论其处于哪个线程;
  • Header_mark_as_shared的首次调用始终在单线程上下文执行;
  • 后续调用Header_mark_as_shared时,读取到的is_shared值始终为1。

待分析代码

#include <stdint.h>

typedef struct Header {
    uint8_t is_shared;
    uint64_t reference_count;
} Header;

void
Header_mark_as_shared(
    Header * const self
) {
    if (!self->is_shared) {
        ++self->reference_count;
        self->is_shared = 1;
    } else {
        __atomic_fetch_add(&self->reference_count, 1, __ATOMIC_RELAXED);
    }
}

void
Header_acquire(
    Header * const self
) {
    if (!self->is_shared) {
        ++self->reference_count;
    } else {
        __atomic_fetch_add(&self->reference_count, 1, __ATOMIC_RELAXED);
    }
}

uint8_t
Header_release(
    Header * const self
) {
    if (!self->is_shared) {
        return !--self->reference_count;
    } else {
        return __atomic_fetch_sub(&self->reference_count, 1, __ATOMIC_ACQ_REL) == 1;
    }
}

uint8_t
Header_is_one(
    Header const * const self
) {
    if (!self->is_shared) {
        return self->reference_count == 1;
    } else {
        return __atomic_load_n(&self->reference_count, __ATOMIC_ACQUIRE) == 1;
    }
}

安全性结论:符合前提条件下完全安全

各函数安全分析

  1. Header_mark_as_shared

    • 首次调用在单线程上下文(前提2),此时is_shared为0,执行的++reference_count和is_shared=1都是单线程操作,无任何竞态风险;
    • 后续调用时,根据前提3,is_shared已固定为1,会进入原子递增分支,__atomic_fetch_add保证了引用计数修改的原子性,不会出现多线程下的计数错误。
  2. Header_acquire

    • 当is_shared=0时,对象处于单线程环境,直接递增计数完全安全,无并发竞争;
    • 当is_shared=1时,对象已跨线程,原子递增操作确保多线程下计数的正确性,__ATOMIC_RELAXED内存序足够满足计数递增的需求(无需额外内存同步,仅需原子性)。
  3. Header_release

    • 单线程阶段(is_shared=0):直接递减计数安全,返回值准确反映计数是否归零;
    • 多线程阶段(is_shared=1):__atomic_fetch_sub搭配__ATOMIC_ACQ_REL内存序,既保证减法操作的原子性,又确保修改对其他线程可见,同时通过返回值正确判断是否为最后一次释放(原计数为1时意味着释放后归零)。
  4. Header_is_one

    • 单线程阶段:直接读取计数判断是否为1,无竞争,结果可靠;
    • 多线程阶段:__atomic_load_n加__ATOMIC_ACQUIRE内存序,确保读取到的是最新的计数值,避免缓存不一致导致的错误判断。

前提条件的核心作用

  • 前提1确保is_shared一旦变为1,所有后续操作都进入原子分支,彻底隔离单线程与多线程操作的交叉风险;
  • 前提2规避了首次设置is_shared时的竞态;
  • 前提3避免了后续调用Header_mark_as_shared时可能出现的分支判断竞态。

内容的提问来源于stack exchange,提问作者João Pires

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 07:03:14