zoukankan      html  css  js  c++  java
  • 《Windows核心编程》第九章——用内核对象进行线程同步

    先举一个有bug的例子:

    #include <iostream>
    #include <windows.h>
    #include <process.h>
    
    using namespace std;
    #define MAX_SIZE 0x500
    
    HANDLE g_hSubmit;
    HANDLE g_hReturn;
    HANDLE g_hStop;
    char g_szInput[MAX_SIZE] = {0};
    
    
    
    unsigned int _stdcall ThreadServer(void* pParam)
    {
        while (TRUE)
        {
            int nWaitRes = WaitForSingleObject(g_hStop, 100);
            if (WAIT_OBJECT_0 == nWaitRes)
                break;
            
    
            WaitForSingleObject(g_hSubmit, INFINITE);
            printf("Recieve:%s
    ", g_szInput);
            SetEvent(g_hReturn);
        }
        SetEvent(g_hStop);
        printf("Set stop
    ");
        return 0;
    }
    
    void main()
    {
        int count = 0;
        g_hSubmit = CreateEvent(NULL, FALSE, FALSE, NULL);
        g_hReturn = CreateEvent(NULL, FALSE, FALSE, NULL);
        g_hStop = CreateEvent(NULL, FALSE, FALSE, NULL);
    
        HANDLE hTheadServer = (HANDLE)_beginthreadex(NULL, 0, ThreadServer, NULL, 0, NULL);
        while (TRUE)
        {
            count++;
            printf("Input:");
            cin.getline(g_szInput, MAX_SIZE);
            SetEvent(g_hSubmit);
            WaitForSingleObject(g_hReturn, INFINITE);
            if (count == 2){
                Sleep(2000);
                SetEvent(g_hStop);
                
                break;
            }
        }
    
        HANDLE hHandle[3];
        hHandle[0] = g_hStop;
        hHandle[1] = hTheadServer;
        WaitForMultipleObjects(2, hHandle, TRUE, INFINITE);
        CloseHandle(hTheadServer);
        CloseHandle(g_hReturn);
        CloseHandle(g_hStop);
        CloseHandle(g_hSubmit);
        getchar();
    
    }

    起初,我想要设置一个事件——g_hStop来通知线程,使得ThreadServer线程能够被主线程停止,但是这里出现了一个问题,如果我刻意让主线程Sleep2秒再去SetEvent,那么等待g_hStop的wait函数就会超时,从而往下继续执行等待Input,而此时主线程已经退出input循环,那么就会死锁。所以我改为使用全局变量来使得Threadserver线程退出:

    #include <iostream>
    #include <windows.h>
    #include <process.h>
    
    using namespace std;
    #define MAX_SIZE 0x500
    
    HANDLE g_hSubmit;
    HANDLE g_hReturn;
    HANDLE g_hStop;
    int g_nCount = 0;
    char g_szInput[MAX_SIZE] = {0};
    
    
    
    unsigned int _stdcall ThreadServer(void* pParam)
    {
        while (TRUE)
        {
            if (g_nCount == 2)
                break;
    
            WaitForSingleObject(g_hSubmit, INFINITE);
            printf("Recieve:%s
    ", g_szInput);
            SetEvent(g_hReturn);
        }
        SetEvent(g_hStop);
        printf("Set stop
    ");
        return 0;
    }
    
    void main()
    {
        g_hSubmit = CreateEvent(NULL, FALSE, FALSE, NULL);
        g_hReturn = CreateEvent(NULL, FALSE, FALSE, NULL);
        g_hStop = CreateEvent(NULL, FALSE, FALSE, NULL);
    
        HANDLE hTheadServer = (HANDLE)_beginthreadex(NULL, 0, ThreadServer, NULL, 0, NULL);
        while (TRUE)
        {
            g_nCount++;
            printf("Input:");
            cin.getline(g_szInput, MAX_SIZE);
            SetEvent(g_hSubmit);
            WaitForSingleObject(g_hReturn, INFINITE);
            if (g_nCount == 2){
                Sleep(2000);
                SetEvent(g_hStop);
                
                break;
            }
        }
    
        HANDLE hHandle[2];
        hHandle[0] = g_hStop;
        hHandle[1] = hTheadServer;
        WaitForMultipleObjects(2, hHandle, TRUE, INFINITE);
        CloseHandle(hTheadServer);
        CloseHandle(g_hReturn);
        CloseHandle(g_hSubmit);
        getchar();
    
    }

    三种方式改进:

    1、如果你非要使用第一种情况,那么请把等待时间设置的长一些,不要是100毫秒,起码要是等待十秒,确保事件触发后,不会超时。

    2、在代码设计的时候,就不要在while中使用两个waitforsingleobject,这种设计就给死锁带来了可能性:

    3、使用waitformultiobject等待两个event之一,然后判断等到的是哪个,从而决定来做什么

     

    一个Mutex和semaphore合用的例子:

    #include <iostream>
    #include <windows.h>
    #include <vector>
    #include <process.h>
    
    using namespace std;
    
    #define MAX_SIZE 10
    
    long g_ServerCount = 0;
    
    class CQueue{
    public:
        CQueue();
        ~CQueue();
    
        void Append();
        void Remove();
    private:
        vector<int> m_vecQueue;
        HANDLE m_hMutex;
        HANDLE m_hSem;
        HANDLE m_hHandles[2];
    };
    
    CQueue g_c;
    
    CQueue::CQueue()
    {
        m_hMutex = CreateMutex(NULL, FALSE, NULL);
        m_hSem = CreateSemaphore(NULL, 0, 10, NULL);
        m_hHandles[0] = m_hMutex;
        m_hHandles[1] = m_hSem;
    }
    
    CQueue::~CQueue()
    {
        CloseHandle(m_hMutex);
        CloseHandle(m_hSem);
    }
    
    void CQueue::Append(){
        DWORD dwRet = WaitForSingleObject(m_hMutex, INFINITE);
        InterlockedExchangeAdd(&g_ServerCount, 1);
        if (dwRet == WAIT_OBJECT_0)
        {
            LONG lPrevCount;
            int bRet = ReleaseSemaphore(m_hSem, 1, &lPrevCount);
            if (bRet)
            {
                m_vecQueue.push_back(g_ServerCount);
                printf("Add element %d
    ", g_ServerCount);
            }
        }
        ReleaseMutex(m_hMutex);
    }
    
    void CQueue::Remove()
    {
        DWORD dwRet = WaitForMultipleObjects(2, m_hHandles, TRUE, INFINITE);
        if (WAIT_OBJECT_0 == dwRet)
        {
            printf("Remove element %d
    ", m_vecQueue.back());
            m_vecQueue.pop_back();
        }
        ReleaseMutex(m_hMutex);
    }
    
    
    unsigned int _stdcall ServerThread(void* pParam)
    {
        while (TRUE)
        {
            Sleep(20);
            g_c.Append();
        }
        
        return 0;
    }
    
    unsigned int _stdcall ClientThread(void* pParam)
    {
        while (TRUE)
        {
            Sleep(20);
            g_c.Remove();
        }
        
        return 0;
    }
    
    void main()
    {
        HANDLE h_Handles[3];
        h_Handles[0] = (HANDLE)_beginthreadex(NULL, 0, ServerThread, NULL, 0, NULL);
        h_Handles[1] = (HANDLE)_beginthreadex(NULL, 0, ServerThread, NULL, 0, NULL);
        h_Handles[2] = (HANDLE)_beginthreadex(NULL, 0, ClientThread, NULL, 0, NULL);
        WaitForMultipleObjects(_countof(h_Handles), h_Handles, TRUE, INFINITE);
        for (int i = 0; i < _countof(h_Handles); i++)
            CloseHandle(h_Handles[i]);
        getchar();
    }
  • 相关阅读:
    有道词典_每日一句_2020/06
    有道词典_每日一句_2020/05
    有道词典_每日一句_2020/04
    有道词典_每日一句_2020/03
    Vue的模板语法之指令1——Vue学习笔记(3)
    Vue的模板语法之插值——Vue学习笔记(2)
    Vue的基本使用——Vue学习笔记(1)
    有道词典_每日一句_2020/02
    有道词典_每日一句_2020/01
    微信小程序 真机调试警告:Some selectors are not allowed in component wxss
  • 原文地址:https://www.cnblogs.com/predator-wang/p/8960622.html
Copyright © 2011-2022 走看看