参考《windows核心编程》(第5版)
有问题的代码
#include <windows.h> #include <iostream> using namespace std; long g_x = 0; DWORD WINAPI ThreadFunc(LPVOID); #define MaxCount 20 int main( void ) { DWORD threadId; HANDLE threadHandle[MaxCount]; for (int i=0; i<MaxCount;++i) { threadHandle[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, &threadId); } Sleep(100); for (int i=0; i<MaxCount;++i) { CloseHandle(threadHandle[i]); } cout <<g_x<<endl; system("pause"); return 0; } DWORD WINAPI ThreadFunc( LPVOID lpParam ) { g_x++; //InterlockedExchangeAdd(&g_x, 1); return TRUE; }潜在风险
g_x++的汇编代码如下
mov eax,dword ptr [g_x (417148h)] add eax,1 mov dword ptr [g_x (417148h)],eax在多线程环境下可能这样执行
1 mov eax,dword ptr [g_x (417148h)] 2 add eax,1 3 mov eax,dword ptr [g_x (417148h)] 4 add eax,1 5 mov dword ptr [g_x (417148h)],eax
在A线程中
1句时eax为1
2句时eax为2
到3句时 切换到B线程
在另一线程中
3句时eax为1
4句时eax为2
5句时g_x为2
当切换到A线程中时,继续执行
mov dword ptr[g_x(417147h)],eax
A线程中的eax为2
则g_x为2
原打算为3
解决方法
#include <windows.h> #include <iostream> using namespace std; long g_x = 0; DWORD WINAPI ThreadFunc(LPVOID); #define MaxCount 20 int main( void ) { DWORD threadId; HANDLE threadHandle[MaxCount]; for (int i=0; i<MaxCount;++i) { threadHandle[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, &threadId); } Sleep(100); for (int i=0; i<MaxCount;++i) { CloseHandle(threadHandle[i]); } cout <<g_x<<endl; system("pause"); return 0; } DWORD WINAPI ThreadFunc( LPVOID lpParam ) { //g_x++; InterlockedExchangeAdd(&g_x, 1); return TRUE; }
InterlockedExchangeAdd函数原型为
LONG __cdecl InterlockedExchangeAdd( _Inout_ LONG volatile *Addend, _In_ LONG Value );参数
Added 变量的地址
Value 增量值
此函数保证递增值操作以原子方式进行。注意,我们必须保证传给此函数的变量地址是经过对齐的,否则此函数可能会失败。(可以使用C函数_aligned_malloc函数)。