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

现代C++无锁线程安全懒式手动单例的内存顺序正确性验证

原子变量实现无锁单例的内存顺序正确性验证

我知道单例模式并非理想方案,现代C++中通常可借助静态局部变量实现线程安全的懒式初始化。但因特定场景需求,尽管我可采用更安全但性能稍逊的带互斥量双重检查锁技术,仍希望验证自己对原子变量及内存顺序的理解。我编写了一段自认为无需强内存屏障的性能最优无锁实现代码,看似可行,但想确认内存顺序的使用是否正确、能否达到预期行为。

代码如下:

// in header file
class DLL_EXPORT MyLogger
{
public:
    void logMessage(std::string message);

private:
    static std::atomic<MyLogger*> sSharedInstance;
};

// in cpp file
constinit std::atomic<MyLogger*> MyLogger::sSharedInstance{nullptr};

MyLogger& MyLogger::sharedInstance()
{
    MyLogger* logger = sSharedInstance.load(std::memory_order_relaxed);
    if (!logger)
    {
        logger = new MyLogger(); // 构造函数为空操作,冗余实例不会造成问题
        MyLogger* previousLogger = nullptr;
        if (!sSharedInstance.compare_exchange_strong(previousLogger, logger, std::memory_order_relaxed, std::memory_order_relaxed))
        {
            // 初始化竞争失败 - 销毁冗余实例
            delete logger;
            logger = previousLogger;
        }
    }

    return *logger;
}

// 在不同线程中调用
void someFunction()
{
    // 可被多线程调用...
    MyLogger::sharedInstance().logMessage("some message");
}

内存顺序与代码正确性分析

基于你构造函数为**空操作(no-op)**这个核心前提,你的代码内存顺序使用是正确的,能达到预期的无锁懒初始化效果:

  • load操作的relaxed顺序:因为构造函数无任何初始化逻辑,不存在实例初始化操作与指针赋值的指令重排风险。原子变量自身的一致性保证了,当CAS成功后,其他线程最终能看到这个非空指针值,relaxed顺序不会影响指针本身的可见性,同时避免了强内存屏障的性能开销。
  • compare_exchange_strong的relaxed顺序:
    • CAS成功时,由于构造函数无操作,不需要同步任何实例初始化的内存操作,relaxed顺序完全足够;
    • CAS失败时,previousLogger会被原子更新为当前的实例指针,我们只需要这个指针的值本身,无需同步其他内存,所以relaxed顺序也没问题。
  • 预期行为达成:多线程竞争初始化时,最多会创建多个冗余实例,但都会被销毁,最终所有线程都会拿到同一个实例的引用,且不会出现使用未初始化实例的情况(因为构造无操作)。

关键注意事项

这个实现的正确性完全依赖构造函数为空操作的前提:如果后续给构造函数添加了任何初始化逻辑(比如成员变量赋值、资源分配),当前的relaxed内存顺序会导致严重问题——其他线程可能看到非空指针,但实例的初始化操作还未完成,进而触发未定义行为。这种情况下需要调整内存顺序:将load改为std::memory_order_acquire,CAS成功时的顺序改为std::memory_order_release,以此保证构造操作的内存可见性。

内容的提问来源于stack exchange,提问作者The Storm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 21:51:12