Mar*_*ins 6 c memory winapi multithreading
昨天关于双重检查锁定的一个问题引发了一连串的想法,让我不确定一个简单的情况.在下面的代码中,是否可以达到printf"不再同步"?在这个简单的例子中,值可能在同一个缓存行上,所以我认为它不太可能(假设开始时可能性> 0%).
如果答案是"不,这是不可能的.",那么我的后续问题是,相当可预见的:为什么不呢?直到昨天我的想法纠结并缠绕在多线程轴上,我认为代码是安全的.但现在我想知道是什么阻止从缓存中读取其中一个变量pa或的变量pb.如果pa, pb指向简单的全局整数变量而不是malloc内存,那会有关系吗?WaitForSingleObject调用是否提供内存屏障?或者指针是否应声明为volatile?这么多问题,句子很少.
更新:我最终找到的信息明确指出,信号同步对象的函数确实使用了内存屏障.应该是显而易见的,但我找不到明确的答案.所以我可以再次欺骗自己相信我理解这一切.
int i1 = 0;
int i2 = 0;
int reads = 0;
int done = 0;
int *pa = NULL;
int *pb = NULL;
HANDLE hSync = NULL;
DWORD WriteThread( LPVOID pvParam )
{
while( !done )
{
WaitForSingleObject( hSync, INFINITE );
(*pa)++;
(*pb)++;
ReleaseSemaphore( hSync, 1, NULL );
}
return 0;
}
DWORD ReadThread( LPVOID pvParam )
{
while( !done )
{
WaitForSingleObject( hSync, INFINITE );
if ( *pa != *pb )
{
printf( "No longer in sync: %d, %d\n", *pa, *pb );
exit( 1 );
}
ReleaseSemaphore( hSync, 1, NULL );
reads++;
}
return 0;
}
int main( int argc, char* argv[] )
{
DWORD dwID;
// malloc'd memory
pa = (int*)malloc( sizeof( int ));
pb = (int*)malloc( sizeof( int ));
// Is a simple global variable different?
//pa = &i1;
//pb = &i2;
*pa = 0;
*pb = 0;
hSync = CreateSemaphore( NULL, 1, 1, NULL );
CreateThread( NULL, 0, WriteThread, NULL, 0, &dwID );
CreateThread( NULL, 0, ReadThread, NULL, 0, &dwID );
while ( *pa < 1000000 )
Sleep( 1 );
done = 1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
内存在哪里并不重要,如果这一切都与缓存一致性有关,那么声明变量 volatile 将无助于修复它。Volatile 的语义对于线程安全来说既不必要也不充分;不要使用它!
在 C/C++ 级别,pa 和 pb 可能会缓存在寄存器中,但在任何函数调用后它们都将被视为陈旧。在 CPU 级别,所有等待函数都使用屏障来确保一切按预期工作。