现在的位置: 首页 > 综合 > 正文

多线程例子_InterlockedExchangeAdd

2018年02月16日 ⁄ 综合 ⁄ 共 1483字 ⁄ 字号 评论关闭

参考《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函数)。

抱歉!评论已关闭.