参考《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
设g_x为1
在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函数)。