Ken*_*enC 5 c c++ volatile visual-c++
我在两个线程之间共享一个变量。我使用 volatile 来避免优化。
\n\n但是,它显示了由于 strcpy 中没有 volatile 的错误。(如下)
\n\n我怎样才能正确修复这个错误?
\n\n有人告诉我要类型转换掉 易失性。\n但是如果我放弃易失性,那么我就失去了易失性的目的......\n最终可能会因优化而出现运行时错误......不是\'是吗?
\n\n非常感谢。
\n\n(代码可直接编译)
\n\nCRITICAL_SECTION CriticalSection;\n\nHANDLE hEvent;\n\nvoid __cdecl MyThread(void* name)\n\n{\n\nchar serName[256];\n\nvolatile char* vptr = (char*) name;\n\n\n\nEnterCriticalSection(&CriticalSection);\n\n\n\nstrcpy(serName, vptr); // error : cannot convert \'volatile\'\n\n// use (and not modify) name\xe2\x80\xa6\n\n\n\nLeaveCriticalSection(&CriticalSection);\n\nSetEvent (hEvent) ;\n\n}\n\n\n\n\nvoid main ()\n\n{\n\nchar name[256] = "abcde";\n\nhEvent = CreateEvent (NULL, false, false, NULL) ;\n\nif (!InitializeCriticalSectionAndSpinCount(&CriticalSection, 0x80000400) )\n\nreturn;\n\n\n\n_beginthread (MyThread, 0, name) ;\n\n\n\nEnterCriticalSection(&CriticalSection);\n\n// access name\xe2\x80\xa6\n\nLeaveCriticalSection(&CriticalSection);\n\n\n\nWaitForSingleObject (hEvent, INFINITE) ;\n\nDeleteCriticalSection(&CriticalSection);\n\nCloseHandle (hEvent);\n\nsystem("pause");\n\n}\nRun Code Online (Sandbox Code Playgroud)\n\n另一方面,我可以编写自己的strcpy来支持易失性。\n但这很奇怪。\n因为如果是这样,那么每次使用易失性时我都必须编写自己的I/O流(或那些复杂的函数)?
\n\n再次感谢您的回答。
\n显然你对“不稳定”的含义还没有清楚的了解。其含义或多或少是“嘿编译器,请注意其他人会更改此变量,因此您不能假设除非您的代码编写它,否则该值将保持不变。此外,其他人可能正在监视此变量,因此当我写入这个变量请不要用无关紧要的假设来做奇怪的事情,因为对于其他观看它的人来说很重要,所以只要写下我想让你写的内容以及当我告诉你这样做时。”
什么时候使用“易失性”很重要?这是一个常见的例子:
volatile int stopflag; // flag will be set by an interrupt handler
void mainloop()
{
stopflag = 0;
while (!stopflag)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
如果三个点中的代码从不接触stopflag并且从不调用具有未知实现的函数,那么编译器可能会试图避免读取循环中的标志,因为查看代码本身似乎不需要读取变量根本...只是设置并永远循环。
另一种情况可能是:
extern volatile unsigned char outloc; // monitored by hardware
...
// emit a wave pulse
for (int x=0; x<256; x++)
outloc = x;
Run Code Online (Sandbox Code Playgroud)
如果没有volatile编译器,则可能会想只写入0xFF该位置而不是写入所有中间值。
请注意,volatile在现代硬件上使用线程同步是不够的。在当今的计算机中,CPU 通常是多核的,因此写入和读取不再是原子操作。虽然在过去(在单核 CPU 上),实际上通常可以使用易失性变量进行线程同步,但现在这是错误的。
您似乎确实有兴趣告诉其他人确实正在读取和写入缓冲区,但在这种情况下,缓冲区的地址是公共的,因此在函数的任何调用中(除非它是内联的或具有已知的实现代码),编译器必须假设缓冲区内容可能已更改或将被未知代码读取。
我敢打赌,线程同步原语是以正确的方式声明的,以确保在您的情况下也是如此(即使strcpy是内联的)。