long g_sum;
unsigned __stdcall ThreadFunc(void* argList){
for(int i = 0; i<100000000; i++){
g_sum++;
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
/* Запускаем 2 потока с одной и той же функцией */
HANDLE hThreads[2];
hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, &ThreadFunc, NULL, 0, NULL);
hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, &ThreadFunc, NULL, 0, NULL);
/* Ждем... */
WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
_tprintf(TEXT("sum: %d\n"), g_sum);
CloseHandle(hThreads[0]);
CloseHandle(hThreads[1]);
return 0;
}
Скорее всего, результат будет всегда разный, между 100 и 200 миллионами (можно увеличить число операций). Если бы каждый поток блокировал g_sum от другого потока на время изменения, то мы бы получили ровно 200 миллионов.
Самое простое, что можно сделать для этого - заменить g_sum++ на InterlockedExchangeAdd(&g_sum, 1). Теперь результат всегда корректен. Блокировка происходит на уровне процессора.
Почему обычный инкремент работает некорректно?
g_sum++ эквивалентно:
mov eax, g_sum;
add eax, 1;
mov g_sum, eax;
То есть, реально это несколько операций. И поток может быть прерван другим потоком после выполнения любой из них. Получается какая-то каша.