zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    手动编译安装nginx
    centoos 安装hadoop集群
    block中如何避免循环引用
    正则表达式
    iOS开发ARC内存管理
    block的内部实现
    Block存储区域
    block的语法
    Collection(数组、字典、集合)
    block捕获自动变量和对象
  • 原文地址:https://www.cnblogs.com/Stephen-Qin/p/11388620.html
Copyright © 2011-2022 走看看