从零理解 C++ 中的原子布尔变量:`std::atomic<bool>` 入门指南

news2025/5/13 22:12:38

请添加图片描述

文章目录

  • 引言:为什么需要原子变量?
  • 一、什么是 `std::atomic<bool>`?
  • 二、为什么不用普通 `bool`?一个反面例子
  • 三、`std::atomic<bool>` 的用法
  • 四、`std::atomic<bool>` 的优势
  • 五、完整示例:多线程文件传输
  • 六、注意事项
  • 七、总结


引言:为什么需要原子变量?

想象这样一个场景:你正在写一个多线程程序,其中一个线程负责传输文件,另一个线程需要实时检查传输是否完成。如果用一个普通的 bool 变量(例如 bool transFileRet = false;)来标记传输结果,可能会遇到意想不到的问题——程序偶尔会“抽风”,明明传输完成了,另一个线程却看不到结果,甚至直接崩溃!

问题的根源在于:普通的变量在多线程环境中不是“线程安全”的。为了解决这个问题,C++11 引入了 std::atomic 模板,而 std::atomic<bool> 正是用于布尔类型的高效线程安全工具。本文将带你一步步理解它的用法和原理。


一、什么是 std::atomic<bool>

🚩1. 原子操作:不可分割的“最小单位”
原子操作指的是在多线程环境中,某个操作一旦开始,就会一次性完整执行,不会被其他线程打断。例如:

transFileRet = true;  // 如果是原子操作,其他线程只会看到赋值前或赋值后的状态

🚩2. std::atomic<bool> 的定义

#include <atomic>  // 必须包含头文件

std::atomic<bool> transFileRet{false};  // 初始化一个原子布尔变量,初始值为 false

transFileRet 是一个布尔变量,但所有对它的操作(读、写、修改)都是原子的。

• 它属于 C++ 标准库,需包含 <atomic> 头文件。


二、为什么不用普通 bool?一个反面例子

🚩错误代码示例

bool transFileRet = false;  // 普通布尔变量

// 线程1:传输完成后设置结果
void worker_thread() {
    // ... 传输文件的逻辑 ...
    transFileRet = true;  // 非原子操作!
}

// 线程2:循环检查结果
void main_thread() {
    while (!transFileRet) {  // 非原子读取!
        // 等待传输完成...
    }
    // 处理传输完成后的逻辑
}

🚩可能的问题

  1. 数据竞争(Data Race)
    如果两个线程同时读写 transFileRet,可能导致未定义行为(程序崩溃、结果错误等)。

  2. 可见性问题
    线程1修改了 transFileRet,但线程2可能因为CPU缓存或编译器优化,永远看不到最新的值。

  3. 指令重排
    编译器或CPU可能优化代码顺序,导致逻辑错误。


三、std::atomic<bool> 的用法

🚩1. 基本操作

std::atomic<bool> flag{false};

// 写入值(原子操作)
flag.store(true);              // 设置为 true
flag.store(false);             // 设置为 false

// 读取值(原子操作)
bool value = flag.load();      // 获取当前值

// 原子地交换值
bool old_value = flag.exchange(true);  // 返回旧值,设置新值为 true

🚩2. 等待与通知(C++20 起支持)
C++20 新增了针对原子变量的等待/通知接口,可以更高效地实现线程同步:

// 线程1:设置标记并通知
flag.store(true);
flag.notify_all();  // 唤醒所有等待的线程

// 线程2:等待标记变为 true
flag.wait(false);  // 当前值为 false 时等待,否则继续执行

四、std::atomic<bool> 的优势

🚩1. 无锁线程安全
• 传统方式需要用 std::mutex 保护布尔变量:

std::mutex mtx;
bool transFileRet = false;

// 写操作
{
    std::lock_guard<std::mutex> lock(mtx);
    transFileRet = true;
}

// 读操作
{
    std::lock_guard<std::mutex> lock(mtx);
    if (transFileRet) { ... }
}

std::atomic<bool> 无需加锁,通过底层硬件指令(如 CAS)实现原子性,性能更高。

🚩2. 内存顺序可控
• 可以通过参数指定内存顺序,平衡性能与一致性(默认是强顺序一致性 memory_order_seq_cst):

flag.store(true, std::memory_order_release);  // 写入时使用 release 语义
bool val = flag.load(std::memory_order_acquire);  // 读取时使用 acquire 语义

🚩3. 避免编译器/CPU 优化
• 确保修改对其他线程立即可见。

• 禁止编译器或CPU对指令进行不安全的重新排序。


五、完整示例:多线程文件传输

#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>

std::atomic<bool> transFileRet{false};  // 原子布尔变量

// 模拟文件传输线程
void transmit_file() {
    std::this_thread::sleep_for(std::chrono::seconds(2));  // 模拟传输耗时
    transFileRet.store(true);  // 原子写入:传输完成
    std::cout << "传输完成!" << std::endl;
}

// 模拟主线程等待结果
void check_status() {
    while (!transFileRet.load()) {  // 原子读取
        std::cout << "等待中..." << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
    std::cout << "检测到传输完成!" << std::endl;
}

int main() {
    std::thread worker(transmit_file);
    std::thread checker(check_status);

    worker.join();
    checker.join();

    return 0;
}

输出示例:

等待中...
等待中...
等待中...
等待中...
传输完成!
检测到传输完成!

六、注意事项

🚩1. 适用场景
std::atomic<bool> 适合简单的状态标记(如完成标志、开关标志)。若需要保护多个变量的复合操作,仍需使用互斥锁。

🚩2. 性能开销
虽然原子操作比锁更高效,但频繁的原子操作(如循环检查)仍可能影响性能。考虑结合条件变量(std::condition_variable)使用。

🚩3. 内存顺序
大多数情况下使用默认的 memory_order_seq_cst 即可。若对性能有极致要求,可学习更弱的内存顺序(如 relaxed)。


七、总结

• 用 std::atomic<bool> 替代普通 bool

当需要在多线程中共享布尔变量时,原子类型是安全且高效的选择。

• 核心优势

无锁、线程安全、高性能、避免优化问题。

• 进一步学习

• 了解其他原子类型(如 std::atomic<int>)。

• 学习内存顺序(C++ Memory Model)。

• 探索 C++20 的原子等待/通知接口。


动手尝试:
将你之前写的某个多线程程序中的普通 bool 变量改为 std::atomic<bool>,观察是否解决了偶发的线程同步问题!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2374955.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

六个仓库合并为一个仓库,保留master和develop分支的bat脚本

利用git subtree可以实现多个仓库合并为一个仓库&#xff0c;手动操作起来太麻烦了&#xff0c;今天花了点时间写了一个可执行的脚本&#xff0c;现在操作起来就方便多了。 1、本地新建setup.bat文件 2、用编辑器打开&#xff08;我用的是Notepad&#xff09; 3、把下面代码…

养生:通往健康生活的桥梁

在生活节奏日益加快的今天&#xff0c;养生已成为维持身心健康的必要手段。从日常饮食到运动锻炼&#xff0c;从睡眠质量到心态调节&#xff0c;每一个环节都对我们的生活品质有着重要影响。以下是一些实用的养生建议&#xff0c;帮助你打造健康生活。 饮食养生&#xff1a;均…

【前端基础】9、CSS的动态伪类(hover、visited、hover、active、focus)【注:本文只有几个粗略说明】

一、什么是伪类 选择器的一种&#xff0c;用于选择处于特定状态的元素。 最常见的现象&#xff1a;鼠标放在某些文字上面&#xff0c;文字就会加上颜色。 鼠标没放上去之前&#xff1a; 鼠标放上去之后&#xff1a; 二、动态伪类 图片来源&#xff08;链接文章也有其他伪…

Simufact Welding重塑新能源汽车电池盒焊接工艺

引言 近年来&#xff0c;新能源汽车行业呈爆发式增长&#xff0c;已然成为全球能源转型与汽车产业升级的核心方向。在新能源汽车中&#xff0c;电池系统占据核心地位&#xff0c;作为电池系统重要组成部分的电池盒&#xff0c;也发挥着不可或缺的作用 。目前&#xff0c;电池盒…

WordPress 网站上的 jpg、png 和 WebP 图片插件

核心功能 1. 转换 AVIF 并压缩 AVIF 将您 WordPress 网站上的 jpg、png 和 WebP 图片转换为 AVIF 格式&#xff0c;并根据您设置的压缩级别压缩 AVIF 图片。如果原始图片已经是 WordPress 6.5 以上支持的 AVIF 格式&#xff0c;则原始 AVIF 图片将仅被压缩。 2. 转换 WebP 并…

如何应对网站被爬虫和采集?综合防护策略与实用方案

在互联网时代&#xff0c;网站内容被恶意爬虫或采集工具窃取已成为常见问题。这不仅侵犯原创权益&#xff0c;还可能影响网站性能和SEO排名。以下是结合技术、策略与法律的综合解决方案&#xff0c;帮助网站构建有效防护体系。 一、技术防护&#xff1a;阻断爬虫的“技术防线”…

AI智慧公园管理方案:用科技重塑市民的“夜游体验”

AI智慧公园管理方案&#xff1a;多场景智能巡检与安全防控 一、背景与痛点分析 夏季夜间&#xff0c;公园成为市民休闲娱乐的核心场所&#xff0c;但管理难度随之激增&#xff1a; 宠物管理失控&#xff1a;未牵绳宠物进入园区&#xff0c;随地排泄、惊扰游客&#xff0c;甚…

LVGL- 按钮矩阵控件

1 按钮矩阵控件 lv_btnmatrix 是 LVGL&#xff08;Light and Versatile Graphics Library&#xff09; v8 中提供的一个非常实用的控件&#xff0c;用于创建带有多个按钮的矩阵布局。它常用于实现虚拟键盘、数字键盘、操作面板、选择菜单等场景&#xff0c;特别适用于嵌入式设…

1. 使用 IntelliJ IDEA 创建 React 项目:创建 React 项目界面详解;配置 Yarn 为包管理器

1. 使用 IntelliJ IDEA 创建 React 项目&#xff1a;创建 React 项目界面详解&#xff1b;配置 Yarn 为包管理器 &#x1f9e9; 使用 IntelliJ IDEA 创建 React 项目&#xff08;附 Yarn 配置与 Vite 建议&#xff09;&#x1f4f7; 创建 React 项目界面详解1️⃣ Name&#xf…

【JVM】从零开始深度解析JVM

本篇博客给大家带来的是JVM的知识点, 重点在类加载和垃圾回收机制上. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f680; …

算法训练营第十四天|110. 平衡二叉树、257. 二叉树的所有路径、404. 左叶子之和、222.完全二叉树的节点个数

110.平衡二叉树 题目 思路与解法 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right class Solution:def isBalanced(self, r…

在 Elasticsearch 中删除文档中的某个字段

作者&#xff1a;来自 Elastic Kofi Bartlett 探索在 Elasticsearch 中删除文档字段的方法。 更多有关 Elasticsearch 文档的操作&#xff0c;请详细阅读文章 “开始使用 Elasticsearch &#xff08;1&#xff09;”。 想获得 Elastic 认证&#xff1f;查看下一期 Elasticsear…

初识Linux · TCP基本使用 · 回显服务器

目录 前言&#xff1a; 回显服务器 TCPserver_v0 TCPserver_v1--多进程版本 TCPserver_v2--多线程版本 前言&#xff1a; 前文我们介绍了UDP的基本使用&#xff0c;本文我们介绍TCP的基本使用&#xff0c;不过TCP的使用我们这里先做一个预热&#xff0c;即只是使用TCP的A…

【layout组件 与 路由镶嵌】vue3 后台管理系统

前言 很多同学在第一次搭建后台管理系统时&#xff0c;会遇到一个问题&#xff0c;layout组件该放哪里&#xff1f;如何使用&#xff1f;路由又该如何设计&#xff1f; 这边会讲一下我的思考过程和最后的结果&#xff0c;大家可以参考一下&#xff0c;希望大家看完能有所收获。…

mobile自动化测试-appium webdriverio

WebdriverIO是一款支持mobile app和mobile web自动化测试框架&#xff0c;与appium集成&#xff0c;完成对mobile应用测试。支持ios 和android两种平台&#xff0c;且功能丰富&#xff0c;是mobile app自动化测试首选框架。且官方还提供了mobile 应用测试example代码&#xff0…

Spring Bean有哪几种配置方式?

大家好&#xff0c;我是锋哥。今天分享关于【Spring Bean有哪几种配置方式&#xff1f;】面试题。希望对大家有帮助&#xff1b; Spring Bean有哪几种配置方式&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring Bean的配置方式主要有三种&#xff…

解析小米大模型MiMo:解锁语言模型推理潜力

一、基本介绍 1.1 项目背景 在大型语言模型快速发展的背景下,小米AI团队推出MiMo系列模型,突破性地在7B参数规模上实现卓越推理能力。传统观点认为32B以上模型才能胜任复杂推理任务,而MiMo通过创新的训练范式证明:精心设计的预训练和强化学习策略,可使小模型迸发巨大推理…

证券行业数字化转型:灵雀云架设云原生“数字高速路”

01 传统架构难承重负&#xff0c;云原生破局成必然 截至2024年&#xff0c;证券行业总资产突破35万亿元&#xff0c;线上交易占比达85%&#xff0c;高频交易、智能投顾等业务对算力与响应速度提出极限要求。然而&#xff0c;以虚拟化为主导的传统IT架构面临四大核心瓶颈&#…

Centos系统详解架构详解

CentOS 全面详解 一、CentOS 概述 CentOS&#xff08;Community Enterprise Operating System&#xff09; 是基于 Red Hat Enterprise Linux&#xff08;RHEL&#xff09; 源代码构建的免费开源操作系统&#xff0c;专注于稳定性、安全性和长期支持&#xff0c;广泛应用于服…

【后端】SpringBoot用CORS解决无法跨域访问的问题

SpringBoot用CORS解决无法跨域访问的问题 一、跨域问题 跨域问题指的是不同站点之间&#xff0c;使用 ajax 无法相互调用的问题。跨域问题本质是浏览器的一种保护机制&#xff0c;它的初衷是为了保证用户的安全&#xff0c;防止恶意网站窃取数据。但这个保护机制也带来了新的…