我在2个线程之间共享一个变量。我使用volatile来避免优化。
但是,它显示了strcpy中没有volatile的错误。 (如下)
如何正确修复此错误?
有些人告诉我要抛弃挥发性物质。 但如果我抛弃挥发物,那么我就失去了挥发性的目的...... 并且最终可能会因为优化而得到运行时错误.....不是吗?
非常感谢。
(代码可以直接编译)
CRITICAL_SECTION CriticalSection;
HANDLE hEvent;
void __cdecl MyThread(void* name)
{
char serName[256];
volatile char* vptr = (char*) name;
EnterCriticalSection(&CriticalSection);
strcpy(serName, vptr); // error : cannot convert 'volatile'
// use (and not modify) name…
LeaveCriticalSection(&CriticalSection);
SetEvent (hEvent) ;
}
void main ()
{
char name[256] = "abcde";
hEvent = CreateEvent (NULL, false, false, NULL) ;
if (!InitializeCriticalSectionAndSpinCount(&CriticalSection, 0x80000400) )
return;
_beginthread (MyThread, 0, name) ;
EnterCriticalSection(&CriticalSection);
// access name…
LeaveCriticalSection(&CriticalSection);
WaitForSingleObject (hEvent, INFINITE) ;
DeleteCriticalSection(&CriticalSection);
CloseHandle (hEvent);
system("pause");
}
另一方面,我可以编写自己的strcpy来支持volatile。 但这很奇怪。 因为如果是这样的话,那么每次使用volatile时我都要编写自己的I / O流(或那些复杂的函数)?
再次回答。
答案 0 :(得分:4)
显然你对“易变”的含义并不清楚。意思或多或少“嘿编译器,请注意其他人将改变这个变量,所以你不能假设,除非你的代码写它,值将保持不变。而且其他人可能正在观察这个变量,所以当我写到这个变量请不要做一些奇怪的事情,假设无关紧要,因为对于其他人来说这很重要,所以只要写下我想要你写的东西,当我告诉你这样做的时候。“
什么时候使用“volatile”很重要?这是一个常见的例子:
volatile int stopflag; // flag will be set by an interrupt handler
void mainloop()
{
stopflag = 0;
while (!stopflag)
{
...
}
}
如果三个点中的代码永远不会触及stopflag
并且从不调用具有未知实现的函数,那么编译器可能会试图避免在循环中读取标志,因为查看代码本身看起来似乎是根本没有必要读取变量......只需设置并永远循环。
另一个案例可能是:
extern volatile unsigned char outloc; // monitored by hardware
...
// emit a wave pulse
for (int x=0; x<256; x++)
outloc = x;
在没有volatile
的情况下,编译器可能只想将0xFF
写入该位置而不是写入所有中间值。
请注意,在现代硬件上使用volatile
进行线程同步是不够的。在今天的计算机中,CPU通常是多核的,因此写入和读取不再是原子操作。虽然在过去(在单核CPU上),实际上通常可以使用volatile变量进行线程同步,但现在这是错误的。
你似乎确实有兴趣告诉缓冲区确实是被其他人读取和写入的,但在这种情况下,缓冲区的地址是公共的,所以在任何函数调用时(除非它是内联的)或者有一个已知的实现代码)编译器必须假定缓冲区内容可能已被更改或将被未知代码读取。
我敢打赌,线程同步原语以正确的方式声明,以确保在您的情况下也是如此(即使内联strcpy
)。
答案 1 :(得分:0)
我可以理解,在某些地方(使用线程时)我们不希望优化发生,为此我们使用“volatile”关键字。
请参阅MSDN了解
要将指针指向的对象声明为const或volatile,请使用以下形式的声明:
const char *cpch;
volatile char *vpch;
要将指针的值(即存储在指针中的实际地址)声明为const或volatile,请使用以下形式的声明:
char * const pchc;
char * volatile pchv;
所以,您可以使用(根据您的需要)
"strcpy(serName, (char *)vptr);" or " char* volatile vptr = (char*) name;"
以上是通过抑制优化来运行代码的解决方案,也不会产生任何错误。现在您不需要自己实现完整的I / O:)
这对我有用。希望,它也可以帮助你......