讲师中心 微信公众号
AI工具推荐 视频效率加速

C++中如何实现线程安全的单例模式?(双重检查锁定或局部静态变量)

千敏姑娘_7925

千敏姑娘_7925

发布时间:2026-01-14 11:49:02

|

503人浏览过

|

来源于php中文网

原创

C++11前双重检查锁定易出问题,主因是编译器/CPU重排序致instance指针提前赋值而对象未构造完,volatile无效且缺乏标准内存模型;C++11起推荐局部静态变量实现,线程安全、异常安全、简洁高效。

c++中如何实现线程安全的单例模式?(双重检查锁定或局部静态变量)

为什么双重检查锁定在C++11之前容易出问题

核心原因是编译器重排序和CPU指令重排可能导致 instance 指针被提前赋值,而对象构造尚未完成。其他线程看到非空指针后直接使用,就会访问未初始化的内存,引发未定义行为。

即使加了 std::mutex,若不配合内存序控制,也无法阻止这种重排。C++11 之前缺乏标准的内存模型支持,volatile 在此场景下完全无效——它既不能禁止重排,也不能提供跨线程同步语义。

  • 老式写法中用 volatile Singleton* instance 是典型误区
  • 没有 std::atomic_thread_fence 或原子操作保障,if (instance == nullptr) 的两次检查之间无同步依据
  • 构造函数抛异常时,instance 可能已置为非空但对象未就绪,后续调用会崩溃

C++11 及以后推荐用局部静态变量(最简且安全)

这是目前最推荐的方式:利用 C++11 标准保证的“函数内局部静态变量的首次初始化是线程安全的”,由编译器自动插入必要的锁和内存屏障,无需手动管理。

它天然规避了双重检查的所有陷阱,代码简洁,性能好(仅首次调用有开销),且支持异常安全(初始化失败时下次仍会重试)。

立即学习“C++免费学习笔记(深入)”;

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance; // ✅ 线程安全,延迟初始化
        return instance;
    }
<p>private:
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
  • 注意:必须是 static Singleton instance;,不是 static Singleton* instance = new Singleton;
  • 该机制依赖编译器实现(如 GCC/Clang/MSVC 均已完整支持),无需额外标志
  • 如果类构造函数可能抛异常,标准规定:每次调用 getInstance() 都会重新尝试初始化,直到成功或程序终止

如果非要手写双重检查锁定,请严格按 C++11+ 规范来

关键点不在“双重检查”,而在原子操作与内存序的精确控制。必须使用 std::atomic 和显式 memory_order,否则仍是错的。

class Singleton {
public:
    static Singleton& getInstance() {
        Singleton* ptr = instance.load(std::memory_order_acquire);
        if (ptr == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);
            ptr = instance.load(std::memory_order_relaxed);
            if (ptr == nullptr) {
                ptr = new Singleton();
                instance.store(ptr, std::memory_order_release);
            }
        }
        return *ptr;
    }
<p>private:
static std::atomic<Singleton*> instance;
static std::mutex mtx;</p><pre class='brush:php;toolbar:false;'>Singleton() = default;
~Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;

};

std::atomic Singleton::instance{nullptr}; std::mutex Singleton::mtx;

  • instance 必须是 std::atomic<singleton></singleton>,不能是裸指针 + volatile
  • 首次读用 memory_order_acquire,写用 memory_order_release,确保构造完成对其他线程可见
  • 内部第二次读可用 memory_order_relaxed,因已持锁,无需额外同步
  • 仍需注意:析构无法自动管理;若需销毁逻辑,得额外设计(如 atexit 或手动清理)

局部静态变量方式的隐藏限制你可能忽略

它虽简单可靠,但有两个实际约束常被忽视:

  • 无法控制销毁时机:对象在 main() 返回后、全局对象析构阶段被销毁,若其他静态对象的析构函数中调用 getInstance(),可能触发二次初始化或访问已销毁对象
  • 不适用于需要自定义内存分配(如 placement new)或跨 DLL 边界的场景:各模块可能拥有独立的局部静态变量实例
  • 若单例依赖其他尚未初始化的静态对象(比如某全局日志器),构造顺序不可控,可能 crash

遇到这些情况,才值得考虑带控制权的双重检查实现,但务必用原子操作,别碰 volatile 或手写汇编屏障。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

相关专题

更多
c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

794

2025.10.23

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

379

2026.04.23

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4478

2023.08.10

空指针异常处理
空指针异常处理

本专题整合了空指针异常解决方法,阅读专题下面的文章了解更多详细内容。

179

2025.11.16

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

40

2026.10.28

Vite 如何搭配 Vue.js
Vite 如何搭配 Vue.js

Vite搭配Vue.js专题汇集创建Vue 3项目、配置开发环境、路径别名、Vue插件、代理、多环境构建与调试的已审核文章,帮助读者完成从初始化到日常开发的配置。

20

2026.10.28

Vite 项目目录怎么看
Vite 项目目录怎么看

Vite项目目录专题汇集入口文件、src源码、public静态资源、路径别名、项目根目录和构建输出目录相关的已审核文章,帮助读者理解各文件夹的用途与引用方式。

40

2026.10.28

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

120

2026.10.22

Gradle Wrapper配置教程
Gradle Wrapper配置教程

本专题介绍Gradle Wrapper的基本作用,涵盖文件组成、生成方法、版本配置和任务调用,帮助你理解项目如何使用指定的Gradle版本,减少不同开发环境带来的构建差异。

80

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn