参考自 http://blog.csdn.net/morewindows/article/details/7429155
// Thread02.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <process.h>
#include <windows.h>
volatile long g_nLoginCount;
unsigned int __stdcall Fun(void *pPM);
const int THREAD_NUM = 50;
unsigned int __stdcall ThreadFun(void *pPM)
{
Sleep(100);
g_nLoginCount++;
Sleep(50);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
int num = 40;
while(num--)
{
g_nLoginCount = 0;
HANDLE handle[THREAD_NUM];
for (int i = 0;i<THREAD_NUM ;i++)
{
handle[i] = (HANDLE)_beginthreadex(NULL,0,ThreadFun,NULL,0,NULL);
}
WaitForMultipleObjects(THREAD_NUM,handle ,TRUE ,INFINITE);
printf("有%d个用户登录后记录结果是%d\n",THREAD_NUM,g_nLoginCount);
}
return 0;
}
运行结果
由于线程执行的并发性,很可能线程A执行到第二句时,线程B开始执行,线程B将原来的值又写入寄存器eax中,这样线程A所主要计算的值就被线程B修改了。这样执行下来,结果是不可预知的——可能会出现50,可能小于50。
因此在多线程环境中对一个变量进行读写时,我们需要有一种方法能够保证对一个值的递增操作是原子操作——即不可打断性,一个线程在执行原子操作时,其它线程必须等待它完成之后才能开始执行该原子操作。这种涉及到硬件的操作会不会很复杂了,幸运的是,Windows系统为我们提供了一些以Interlocked开头的函数来完成这一任务(下文将这些函数称为Interlocked系列函数)。
下面列出一些常用的Interlocked系列函数:
1.增减操作
LONG__cdeclInterlockedIncrement(LONG volatile* Addend);
LONG__cdeclInterlockedDecrement(LONG volatile* Addend);
返回变量执行增减操作之后的值。
LONG__cdec InterlockedExchangeAdd(LONG volatile* Addend, LONGValue);
返回运算后的值,注意!加个负数就是减。
2.赋值操作
LONG__cdeclInterlockedExchange(LONG volatile* Target, LONGValue);
Value就是新值,函数会返回原先的值。
修改代码为:
unsigned int __stdcall ThreadFun(void *pPM)
{
Sleep(100);
//g_nLoginCount++;
InterlockedIncrement((LPLONG)&g_nLoginCount);
Sleep(50);
return 0;
}
将THREAD_NUM = 100;
则结果如下