Я вижу много потоков на этом форуме, занимающихся вопросом, нужно ли нам использовать синхронизацию при доступе к примитивным типам данных из нескольких потоков: вопрос 1, вопрос 2, вопрос 3, вопрос 4...
Поэтому я написал небольшой тест, чтобы проверить это:
Я запускал его более часа на процессоре Intel(R) Core(TM) i7 CPU 860 @2.80GHz
который работает с 4 физическими ядрами:
#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;
}
и я не потерпел неудачу. Итак, как бы вы это объяснили?
В Intel чтение и запись для выровненных слов - это атомные операции (атомарные в том смысле, что другие процессоры будут видеть либо оригинал, либо новое значение).
Обратите внимание, что это не означает, что вы не должны предоставлять механизм синхронизации. Этот тестовый пример - это тот, в котором потоки просто записывают и считывают новые значения в одну и ту же переменную. Если они выполняли какую-то операцию, связанную с чтением/записью для обновления, она могла потерпеть неудачу (скажем, что 10 потоков увеличивают эту переменную на 100, переменная в конце, возможно, не была увеличена на 1000 баллов!) И что нет другие переменные в игре (где переупорядочение компилятора/процессора может вызвать другие проблемы).
gdwSharedVal01
после обновления, он не будет иметь того же значения. Моей главной заботой была целостность самого примитивного типа (за одну операцию).