volatile(防止编译器对代码进行优化,常用于多线程环境中)

一.单词解释

  • adj.易变的;无定性的;无常性的;可能急剧波动的

二.使用说明:

volatile表示这变量可能会被意想不到地改变,提示编译器别优化老子,编译器就不会去假设这个变量的值了。

建议你用volatile修饰在多个线程中使用的原生类型变量

举例说明:

class Gadget
{
public:
void Wait()
{
  while (!flag_)
  {
  Sleep(1000); // sleeps for 1000 milliseconds
  }
}
void Wakeup() {   flag_ = true; } ... private: bool flag_; };

上面代码中的Wait()想要实现每隔一秒对flag_进行判断,如果flag_被另外的线程改为true的话,就会跳出循环.

但实际上这样设计是存在问题的,原因就在于while循环中,编译器认为flag_的值不会改变,那么它会把flag_的值从内存中缓存到寄存器中,这样的话就提高了访问效率.这对于单线程是很好的优化,但是这样会让程序变得不正确.当另一个线程改变了内存中flag_的值时,while循环还是访问寄存器中的值,这样就导致了出现问题.

C和C++给你提供了显式禁用这种缓存优化的机会。如果你声明变量是使用了volatile修饰符,编译器就不会把这个变量缓存在寄存器里——每次访问都将去存取变量在内存中的实际位置。这样你要对Gadget的Wait/Wakeup做的修改就是给flag_加上正确的修饰:

class Gadget
{
public:
... as above ...
private:
volatile bool flag_;
};

参考文章:https://blog.csdn.net/xuwentao37x/article/details/27804169

 三代码示例

#include <iostream>
#include <windows.h>

using namespace std;

class Test
{
private:
    volatile bool m_bFlag; //在VS下不加volatile也可以正确执行,不过为了安全还是需要加上的.
public:
    Test()
    {
        m_bFlag = false;
    }
    void Wait()
    {
        while (!m_bFlag)
        {
            cout << "I'm Sleeping" << endl;
            Sleep(1000);
        }
        cout << "I'm awake" << endl;
    }

    void WakeUp()
    {
        m_bFlag = true;
    }
};

DWORD WINAPI ThreadFun2(void *param)
{
    Test *tThread = (Test *)param;
    tThread->WakeUp();
    return 0;
}

DWORD WINAPI ThreadFun1(void *param)
{
    Test *tThread = (Test *)param;
    tThread->Wait();
    return 0;
}

//用两个子线程实现,发现两个子线程之间的生存期是相互独立的.它们只受主线程的影响.
int main()
{
    Test t;
    HANDLE h[2];
    h[0] = CreateThread(NULL, 0, ThreadFun1, &t, 0, NULL);
    Sleep(10);//如果不加这个Sleep,多数情况下会先打印Sleeping,然后打印awake,但是也有情况会直接打印awake.
    h[1] = CreateThread(NULL, 0, ThreadFun2, &t, 0, NULL);
    WaitForMultipleObjects(2, h, TRUE, INFINITE);
    return 0;
}

关于这个例子,多线程相关的探讨可以参见自己总结的这篇文章:https://i-beta.cnblogs.com/posts/edit-done;postId=12708937

新战场:https://blog.csdn.net/Stephen___Qin
原文地址:https://www.cnblogs.com/Stephen-Qin/p/11388620.html