使用 C++ 测试对原始数据类型的同步锁的需求
Posted
技术标签:
【中文标题】使用 C++ 测试对原始数据类型的同步锁的需求【英文标题】:Testing the need of synchronization lock on primitive data types with C++ 【发布时间】:2014-01-23 21:39:44 【问题描述】:我在这个论坛上看到很多线程都在处理从多个线程访问原始数据类型时是否需要使用同步的问题:Question 1、question 2、question 3、question 4 ...
所以我写了一个小测试来验证这一点:
我在运行 4 个物理内核的 CPU Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz
上运行了一个多小时:
#define MULTIPLIC_VAL 17
DWORD gdwSharedVal01 = MULTIPLIC_VAL;
DWORD WINAPI thread001(LPVOID lpParameter);
//Begin threads
for(int i = 0; i < 30; i++)
DWORD dwThreadId;
HANDLE hThread = ::CreateThread(NULL, 0, thread001, NULL, 0, &dwThreadId);
if(hThread)
::CloseHandle(hThread);
else
_tprintf(L"ERROR: CreateThread error %d\n", ::GetLastError());
//Wait
getchar();
BOOL checkSharedValue()
//RETURN:
// = TRUE if value is OK
if((gdwSharedVal01 % MULTIPLIC_VAL) == 0)
return TRUE;
return FALSE;
DWORD WINAPI thread001(LPVOID lpParameter)
srand((UINT)time(NULL));
DWORD dwThreadID = ::GetCurrentThreadId();
_tprintf(L"Thread %d began...\n", dwThreadID);
for(;;)
//Set value
DWORD v = rand();
v <<= 16;
v ^= rand();
v = v / MULTIPLIC_VAL;
gdwSharedVal01 = v * MULTIPLIC_VAL;
//Check value
if(!checkSharedValue())
//Failed
_tprintf(L"FAILED thread %d\n", dwThreadID);
return 0;
我没有失败。那你怎么解释呢?
【问题讨论】:
某些处理器(以 x86 为主要示例)为多线程程序提供的保证比其他处理器或 C 或 C++ 标准要求的多很多。 我会这样解释,有时未定义行为的结果就是按照您的预期行事。 【参考方案1】:在 Intel 中,对对齐字的读取和写入是原子操作(原子的意思是其他处理器将看到原始值或新值)。
请注意,这并不意味着您不应该提供同步机制。这个测试用例是线程只是将新值写入和读取到同一个变量中的测试用例。如果他们提供某种涉及读/写更新的操作,它可能会失败(比如 10 个线程将变量增加 100,最后的变量可能没有总共增加 1000!)并且没有其他变量(编译器/cpu 重新排序可能导致其他问题)。
【讨论】:
嗯,是的,很明显,如果同一个线程在更新后尝试从我的gdwSharedVal01
变量中读取,它将不会具有相同的值。我主要关心的是原始类型本身的完整性(每个操作)。
所以,比如说,如果我确定我的代码将在 x86/x64 Windows-only 机器上运行,Windows XP 及更高版本,我可以安全地跳过同步作为我给出的示例上面?
@c00000fd:那个特定的例子会起作用。在它周围添加最少量的复杂性,它很可能会失败。 int
初始化为 0 并由一个线程设置为 1 是一种有效的同步机制吗?仅当唯一的共享状态是 int
。以上是关于使用 C++ 测试对原始数据类型的同步锁的需求的主要内容,如果未能解决你的问题,请参考以下文章