zoukankan      html  css  js  c++  java
  • 《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
    ", 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
    ", g_nCount);
        getchar();
    }

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

    •  条件变量的使用
    #include <iostream>
    #include <windows.h>
    #include <vector>
    #include <process.h>
    #include "Queue.h"
    
    using namespace std;
    CQueue g_Queue;
    SRWLOCK g_srwLock;
    CONDITION_VARIABLE g_cvProduce;
    CONDITION_VARIABLE g_cvConsume;
    
    int g_nCount = 0;
    int g_nWriterCount = 0;
    int g_nReaderCount = 0;
    
    unsigned int _stdcall WriterThread(void* pParam)
    {
        g_nWriterCount++;
        //printf("Enter writerthread-%d
    ", g_nWriterCount);
        while (TRUE)
        {
            Sleep(1000);
            AcquireSRWLockExclusive(&g_srwLock);
            if (g_Queue.IsFull())
            {
                printf("Queue is full..
    ");
                SleepConditionVariableSRW(&g_cvProduce, &g_srwLock, INFINITE, 0);
            }
            /*else
            {
                
            }*/
            g_Queue.AddElement(g_nCount);
            printf("Produce element:%d
    ", g_nCount);
            g_nCount++;
            ReleaseSRWLockExclusive(&g_srwLock);
            WakeConditionVariable(&g_cvConsume);
        }
        return 0;
    }
    
    unsigned int _stdcall ReaderThread(void* pParam)
    {
        g_nReaderCount++;
        //printf("Enter readerthread-%d
    ", g_nReaderCount);
        while (TRUE)
        {
            Sleep(2000);
            //这里使用的例子和书中的例子有所不同,书中的例子中的ReaderThread仅仅是读取队列中的内容,而这里

         //会去修改队列的内容,所以不能使用AcquireSRWLockShared. AcquireSRWLockExclusive(&g_srwLock); if (g_Queue.IsEmpty()) { printf("Queue is empty.. "); SleepConditionVariableSRW(&g_cvConsume, &g_srwLock, INFINITE, 0); } /*else { }*/ printf("Consume element:%d ", g_Queue.DelElement()); ReleaseSRWLockExclusive(&g_srwLock); WakeAllConditionVariable(&g_cvProduce);//don't use wakeconditionvariable(). } return 0; } void main() { InitializeSRWLock(&g_srwLock); HANDLE hWriter1 = (HANDLE)_beginthreadex(NULL, 0, WriterThread, NULL, 0, NULL); HANDLE hWriter2 = (HANDLE)_beginthreadex(NULL, 0, WriterThread, NULL, 0, NULL); HANDLE hReader1 = (HANDLE)_beginthreadex(NULL, 0, ReaderThread, NULL, 0, NULL); HANDLE hReader2 = (HANDLE)_beginthreadex(NULL, 0, ReaderThread, NULL, 0, NULL); HANDLE hReader3 = (HANDLE)_beginthreadex(NULL, 0, ReaderThread, NULL, 0, NULL); HANDLE hArray[5] = { hWriter1, hWriter2, hReader1, hReader2, hReader3 }; WaitForMultipleObjects(5, hArray, TRUE, INFINITE); CloseHandle(hWriter1); CloseHandle(hWriter2); CloseHandle(hReader1); CloseHandle(hReader2); CloseHandle(hReader3); getchar(); }

  • 相关阅读:
    C/C++解题常用STL大礼包 含vector,map,set,queue(含优先队列) ,stack的常用用法
    PAT甲级1018留坑——第一个测试点未过(Dijikstar+Dfs)
    PAT甲级1019水题飘过
    微信该公众号提供的服务出现故障
    The valid characters are defined in RFC 7230 and RFC 3986
    eclipse中Web Deployment Assembly与build path作用
    Invalid bound statement (not found)
    springmvc获取bean
    mac/linux查询网络端口占用
    SiteMesh使用(2.4.2)
  • 原文地址:https://www.cnblogs.com/predator-wang/p/8905815.html
Copyright © 2011-2022 走看看