如果有两个线程访问全局变量,那么许多教程都说使变量volatile变为阻止编译器将变量缓存在寄存器中,从而无法正确更新.但是,访问共享变量的两个线程是通过互斥锁来调用保护的东西不是吗?但是在这种情况下,在线程锁定和释放互斥锁之间,代码处于一个关键部分,只有那个线程可以访问变量,在这种情况下变量不需要是volatile?
那么多线程程序中volatile的用途/目的是什么?
有一对夫妇在这个网站,询问使用是否问题volatile变量原子/多线程访问是可能的:见这里,这里,还是这里的例子.
现在,符合C(++)标准的答案显然没有.
但是,在Windows和Visual C++编译器上,情况似乎并不那么清楚.
微软特定
声明为volatile的对象是(...)
- 对volatile对象的写入(volatile write)具有Release语义; 对全局或静态对象的引用?在编译二进制文件中的易失性写入之前,将在写入指令序列中的易失性对象之前发生这种情况.
- 读取volatile对象(volatile read)具有Acquire语义; 对全局或静态对象的引用 ?在读取编译二进制文件中的易失性读取之后,将在读取指令序列中的易失性存储器之后发生这种情况.
这允许volatile对象用于多线程应用程序中的内存锁定和释放.
[强调我的]
现在,读到这一点,在我看来,MS编译器将处理一个易变量变量,就像std::atomic即将推出的C++ 11标准一样.
然而,在对我的回答的评论中,用户Hans Passant写道:"那篇MSDN文章非常不幸,这是错误的.你不能用volatile来实现锁定,甚至不能使用微软的版本.(...)"
请注意:MSDN中给出的示例看起来很可疑,因为您通常无法在没有原子交换的情况下实现锁定.(正如亚历克斯所指出的那样)这仍然留下了问题.有关此MSDN文章中给出的其他信息的有效性,特别是对于此处和此处的用例.)
此外,还有Interlocked*函数的文档,尤其是InterlockedExchange带有volatile(!?)变量并进行原子读取和写入.(注意我们在SO上有一个问题 - 何时应该使用InterlockedExchange? - 没有权威性地回答是否需要这个函数来进行只读或只写原子访问.)
更重要的是,volatile上面引用的文档以某种方式暗示"全局或静态对象",我认为"真正的" 获取/释放语义应该适用于所有值. …
我正在阅读关于使用bool进行线程控制的问题,并且被@eran的这个答案所吸引:
使用volatile仅在单核上足够,其中所有线程使用相同的缓存.在多核上,如果在一个核上调用stop()而在另一个核上执行run(),则CPU缓存可能需要一些时间来进行同步,这意味着两个核可能会看到两个不同的isRunning_视图.
如果您使用同步机制,它们将确保所有缓存获得相同的值,代价是暂停程序一段时间.性能或正确性对您来说更重要取决于您的实际需求.
我花了一个多小时搜索一些声明,说同步原语强制缓存一致但失败了.我最接近的是维基百科:
关键字volatile不保证内存屏障可以强制执行缓存一致性.
这表明内存屏障确实强制缓存一致性,并且由于一些同步原语是使用内存屏障(同样来自维基百科)实现的,这是一些"证据".
但我不知道是否相信这一点与否,并确保我不会误解它.
有人可以澄清一下吗?
我刚刚问了一个涉及volatile:volatile array c ++的问题
然而,我的问题产生了关于什么volatile做的讨论.
有人声称在使用时CreateThread(),您不必担心volatiles.另一方面,Microsoft提供了一个volatile使用两个线程创建时的示例CreateThread().
我创建在Visual C下面的示例++速成2010年,如果你将其标记不要紧done作为volatile或不
#include "targetver.h"
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <tchar.h>
using namespace std;
bool done = false;
DWORD WINAPI thread1(LPVOID args)
{
while(!done)
{
}
cout << "Thread 1 done!\n";
return 0;
}
DWORD WINAPI thread2(LPVOID args)
{
Sleep(1000);
done = 1;
cout << "Thread 2 done!\n";
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD …Run Code Online (Sandbox Code Playgroud) 使用std::thread运行它运行一个无限循环,是有办法,如果线程被要求参加环可以查询的方法......还是我必须手动添加一个"了ExitThread"标志?
换句话说,isJoined看起来像什么(未经测试的伪代码):
std::atomic<int> global_counter (0);
void Run()
{
while(!isJoined())
{
doSomething();
++global_counter;
}
}
int main()
{
thread t(Run);
Sleep(10000);
t.join();
cout << "Iterated " << global_counter << "times" << endl;
}
Run Code Online (Sandbox Code Playgroud) 我知道这里有很多关于volatile的问题,但是我没有找到任何特定于这种情况的东西.我正在使用微控制器.我知道当我在ISR中修改一个全局变量并在我的main函数中读取它时,我必须使用volatile限定符.我也觉得非常适合记忆障碍,比赛条件等.
但是如果我只在主函数中写入一个全局变量(中断被禁用以强制执行原子写入)并且我正在我的ISR中读取和写入它.
为了给出一个明确的例子假设这个代码:
int state = 0;
ISR()
{
switch(state)
{
case 0:
//do something
state=nextState; //go to another state
break;
case 1:
//do something
state=nextState; //go to another state
break;
case 2:
//do something
state=nextState; //go to another state
break;
//...some more states
default:
state=0;
break;
}
}
main(void)
{
while(true)
{
//do lots of stuff
if(someCondition)
{
EnterCriticalSection(); //Disable IRQs and memorybarrier
//write to global shared variable state here!!!
state=0;
ExitCriticalSection(); //Enable IRQs again
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以必须在这里挥发吗? …