C++ volatile关键字

volatile的作用

volatile关键字在C++中用于指示编译器,变量的值可能在程序的直接控制之外被修改。它告诉编译器不要对这些变量优化,因为它们的值可以由不可预见的源(如硬件或其他并发线程)改变。

volatile关键字的主要作用就是确保对被标记为volatile的变量的每次读取和写入都直接从内存进行,而不依赖于寄存器中的可能已缓存的值。这样可以保证该变量的值是最新的,适用于那些可能在程序的控制之外被修改的变量

volatile的用法

  1. 硬件访问:当程序需要直接与硬件设备交互时,硬件的寄存器可能会在程序未显式修改的情况下发生变化。使用volatile可以保证每次读取或写入都是直接对硬件寄存器操作,确保数据的实时正确性。

    // 假设0x40001000是计时器寄存器的内存地址
    volatile int* timer = reinterpret_cast<volatile int*>(0x40001000);
    
    void waitForTimer() {
        while (*timer != 0) {
            // 此处空循环等待计时器寄存器值变为0
        }
    }
    
  2. 多线程编程:在多线程环境中,某个线程可能修改由多个线程共享的变量。通过将这些共享变量声明为volatile,可以防止编译器对这些变量的读写操作进行优化,确保每次都直接从内存中读取最新值。

  3. 中断服务程序:在编写中断服务程序(ISR)时,ISR可能会修改在主程序中使用的变量。声明这些变量为volatile可以确保主程序总是获取到由ISR更新的最新值。

volatile的注意事项

  1. 不是并发原语volatile关键字并不能保证变量的访问是线程安全的。它不提供原子操作或内存屏障等同步机制。在多线程环境下,对于共享数据的访问通常需要使用互斥锁(如std::mutex)或原子操作(如std::atomic)。

  2. 函数中的使用:如果对象被声明为volatile,则只能调用那些特别标记为适用于volatile对象的成员函数。如果你尝试用一个声明为volatile的对象来调用一个未经过volatile修饰的成员函数,这将导致编译错误。

    class Widget {
    public:
        int data;
        void update() { /* 更新数据的操作 */ }
        void safeUpdate() volatile { /* 针对volatile对象安全的更新操作 */ }
    };
    
    int main() {
        volatile Widget myWidget;
        // myWidget.update();  // 错误:不能用volatile对象调用非volatile函数
        myWidget.safeUpdate();  // 正确:该函数声明为volatile
        return 0;
    }
    
  3. 性能考虑:由于volatile阻止了编译器进行相关优化,过度使用可能会导致程序性能下降。只有在确实需要时才应该使用volatile,避免在不需要其语义时使用它。

  4. 类型安全:使用volatile 时,还应注意类型安全,特别是在将volatile类型与非volatile类型混合使用时。当声明一个变量为volatile时,你告诉编译器这个变量的值可能会在程序的直接控制之外被改变,因此每次访问都需要直接从内存中读取。这种行为对于简单的数据类型(如intfloat等)来说是直接的,但对于复杂的数据类型(如类实例)来说,则复杂得多。类的volatile修饰符影响整个对象,包括其所有方法和内部状态。

    class Widget {
    public:
        int data;
        void update() { /*...*/ }
    };
    
    Widget regularWidget;
    volatile Widget volatileWidget = regularWidget;  // 错误,通常不被允许
  5. 指针:
    a. 指向volatile类型的指针(Volatile Pointed-to Type):这种情况下,指针指向的数据是volatile的。这意味着指针本身可以改变指向不同的地址,但访问指针指向的数据时,每次都需要从内存中直接读取,不能优化。

    int volatile *ptrVolatileData;

    在这个例子中,ptrVolatileData可以指向不同的地址,但它指向的整数必须被当作volatile处理,即每次通过指针读写时都需要从其内存地址访问。
    b. volatile 指针(Volatile Pointer):这种情况下,指针本身是volatile的,意味着指针的值(即它指向的地址)可能会被程序外部因素改变,但指向的数据不是volatile

    int * volatile ptrVolatile;

  • 25
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LIHAORAN99

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值