大话C++之:volatile关键字

本文解释了volatile关键字在C++中的作用,尤其是在处理内存顺序问题和多线程环境中的变量更新。随着C++11引入std::atomic,volatile的角色被std::memory_order所取代,强调了原子性和内存屏障的重要性。
摘要由CSDN通过智能技术生成

volatile关键字是个老生常谈的话题了,C/C++面试必问。但还是有很多人搞不懂volatile是干什么的,定义都知道:volatile 关键字在 C 和 C++ 语言中被用来指示编译器,不要对该变量进行优化,被其修饰的变量可能会在程序的控制之外被改变。

先说结论,有了C++11引入的std::atomic,我们就已经不需要volatile了。volatile常用于C++11之前的时代,或者使用C语言的嵌入式项目里。

volatile实质上解决的是内存顺序的问题,关于内存顺序的详解可以先看下大白话C++之:深入理解多线程内存顺序(Memory Order)

既然volatile的作用不好理解,那我们干脆直接从原理的角度看下编译器会对volatile做什么。

当一个变量被定义为volatile后,实质上编译器会做3件事情:

  • 在volatile变量的所在地方插入一个内存屏障,前面的指令不能重排到屏障之后,后面的指令也不能重排到屏障之前。
  • 读取volatile变量时,直接从内存中读,而不是从CPU Cache中读。
  • 更新volatile变量时,不仅要更新CPU Cache中的值,还要更新到内存里,强制刷新其他CPU核心里的Cache,让其他CPU核心能立马看到这个volatile变量的最新值。

此处的CPU Cache指L1 Cache, L2 Cache , L3 Cache等,如下图所示,不了解CPU Cache的需要移步大白话C++之:深入理解多线程内存顺序(Memory Order)了解下😁。

在这里插入图片描述

Talk is cheap, let’s see the code.

在这里插入图片描述

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

// 模拟硬件信号状态,使用volatile关键字
volatile bool hardwareSignal = false;

// 硬件信号检测函数
void detectHardwareSignal() {
    while (true) {
    	// 如果hardwareSignal没有volatile属性,
    	// 此处读取hardwareSignal就会从CPU Cache里读,
    	// 无法及时看到其他CPU核心更新的hardwareSignal最新值。
    	//
    	// 但是因为volatile属性,会从内存读取hardwareSignal的值。
        if (hardwareSignal) {
            std::cout << "Hardware signal detected!" << std::endl;
            hardwareSignal = false; // 重置信号
        }
        // 延迟一段时间,模拟持续检测
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

// 主函数
int main() {
    // 启动线程,模拟硬件信号检测
    std::thread signalThread(detectHardwareSignal);

    // 模拟从其他线程触发硬件信号
    // main函数本身就是一个线程
    std::this_thread::sleep_for(std::chrono::seconds(2));

	// 如果hardwareSignal没有volatile属性,
	// 此处只会更新CPU Cache里的hardwareSignal,
	// detectHardwareSignal线程里看到的hardwareSignal仍然是false。
	// 
	// 但是因为volatile属性,此处会更新内存里hardwareSignal的值。
    hardwareSignal = true;

    // 等待线程完成
    signalThread.join();

    return 0;
}

读过大白话C++之:深入理解多线程内存顺序(Memory Order)的同学看到这里,其实应该已经明白了,volatile变量相当于std::memory_order里的memory_order_seq_cst,只是不保证操作的原子性,volatile常常需要与pthread_mutex_t一起搭配食用。

所以当C++11引入std::atomic后,我们就可以使用std::atomi搭配std::memory_order来取代volatilepthread_mutex_的组合啦。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值