一.单词解释
adj.易变的;无定性的;无常性的;可能急剧波动的
二.使用说明:
volatile表示这变量可能会被意想不到地改变,提示编译器别优化老子,编译器就不会去假设这个变量的值了。
建议你用volatile修饰在多个线程中使用的原生类型变量
举例说明:
void Wakeup(){flag_ = true;}...private:bool flag_;};class Gadget{public:void Wait(){while (!flag_){Sleep(1000); // sleeps for 1000 milliseconds}}
上面代码中的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_;};
参考文章:/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-/posts/edit-done;postId=12708937