《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();
}
原文地址:https://www.cnblogs.com/predator-wang/p/8960622.html