《Windows核心编程》第八章——用户模式下的线程同步

下面起了两个线程,每个对一个全局变量加500次,不假思索进行回答,会认为最后这个全局变量的值会是1000,然而事实并不是这样:

#include<iostream>
#include <process.h>
#include <windows.h>

using namespace std;
typedef unsigned int (_stdcall *PThreadFunc)(void*);
int g_nCount = 0;

unsigned int _stdcall ThreadTest1(void*)
{
    for (int i = 0; i < 500; i++)
    {
        g_nCount++;
    }
    
    return 0;
}

unsigned int _stdcall ThreadTest2(void*)
{
    for (int i = 0; i < 500; i++)
    {

        g_nCount++;
    }
    return 0;
}

void main()
{
   g_nCount = 0;
   HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, ThreadTest1, NULL, 0, NULL); HANDLE h2 = (HANDLE)_beginthreadex(NULL, 0, ThreadTest2, NULL, 0, NULL); HANDLE hs[2] = {h1, h2}; WaitForMultipleObjects(2, hs, TRUE, INFINITE); CloseHandle(h1); CloseHandle(h2); 
  printf("Global count:%d\n", g_nCount); getchar(); 
}

然而运行多次、每次结果都不同,而且,几乎不会等于1000:

造成这种现象的原因很简单,就是g_nCount在进行自增的时候没有实现原子操作,g_nCount的本质其实是:

  • Interlocked函数

为了保证自增的原子性,改为使用Interlocked函数:

#include<iostream>
#include <process.h>
#include <windows.h>

using namespace std;
typedef unsigned int (_stdcall *PThreadFunc)(void*);
int g_nCount = 0;

unsigned int _stdcall ThreadTest1(void*)
{
    for (int i = 0; i < 500; i++)
    {
        //Sleep(12);
        //g_nCount ++;
        InterlockedIncrement((volatile unsigned long long*)&g_nCount);
    }
    
    return 0;
}

unsigned int _stdcall ThreadTest2(void*)
{
    for (int i = 0; i < 500; i++)
    {
        //Sleep(10);
        //g_nCount ++;
        InterlockedIncrement((volatile unsigned long long*)&g_nCount);
    }
    return 0;
}

void main()
{
    g_nCount = 0;
    HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, ThreadTest1, NULL, 0, NULL);
    HANDLE h2 = (HANDLE)_beginthreadex(NULL, 0, ThreadTest2, NULL, 0, NULL);
    HANDLE hs[2] = { h1, h2 };
    WaitForMultipleObjects(2, hs, TRUE, INFINITE);
    CloseHandle(h1);
    CloseHandle(h2);
    
    printf("Global count:%d\n", g_nCount);
    getchar();
}

这样就保证了自增的原子性。

猜你喜欢

转载自www.cnblogs.com/predator-wang/p/8905815.html
今日推荐