1. 程式人生 > >C++多線程同步技巧(二)--- 事件

C++多線程同步技巧(二)--- 事件

create include 解鎖 signed 選擇 參數 bre tdi 人工

簡介

Windows在線程同步方面提供了多種信號處理機制,其中一種便是使用 CreateEvent() 函數創建事件,然後使用信號控制同步。其中將事件變為有信號可使用 SetEvent() 函數,將事件信號復位(變為無信號)可使用 ResetEvent() 函數,信號可以配合 WaitForSingleObject() 函數進行控制,當有信號時,此函數便會放行;無信號時,此函數會將阻塞。

提示: CreateEvent() 函數的參數 bManualReset 的含義是信號是否由人工復位,如果選擇true,則信號必須手動采用ResetEvent() 函數進行復位操作,在這種情況下,可能會偶爾出現線程不同的情況,問題出在可能同時會有多個線程穿過 WaitForSingleObject()

函數,導致復位失效,所以在這種情況下,為確保萬無一失,我們一般會再添加一個限制條件,例如臨界區互斥體;如果選擇的是false,則當一個信號經過 WaitForSingleObject() 函數的時候,函數會自動將事件信號復位。

代碼樣例

  • bManualReset參數為false
////////////////////////////////
//
// FileName : ThreadEventDemo.cpp
// Creator : PeterZheng
// Date : 2018/9/23 18:00
// Comment : The usage of "CreateEvent"
//
////////////////////////////////

#pragma once

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <windows.h>

using namespace std;

DWORD WINAPI func1(LPVOID lpParam);
DWORD WINAPI func2(LPVOID lpParam);

HANDLE hEvent = NULL;
unsigned int unCount = 0;

DWORD WINAPI func1(LPVOID lpParam)
{
    while (true)
    {
        WaitForSingleObject(hEvent, INFINITE);
        ResetEvent(hEvent);
        if (unCount < 100)
        {
            unCount++;
            Sleep(10);
            cout << "Count: " << unCount << endl;
            SetEvent(hEvent);
        }
        else
        {
            SetEvent(hEvent);
            break;
        }
    }
    return 0;
}

DWORD WINAPI func2(LPVOID lpParam)
{
    while (true)
    {
        WaitForSingleObject(hEvent, INFINITE);
        ResetEvent(hEvent); // 重置事件為無信號狀態
        if (unCount < 100)
        {
            unCount++;
            Sleep(10);
            cout << "Count: " << unCount << endl;
            SetEvent(hEvent); // 設置事件為有信號狀態
        }
        else
        {
            SetEvent(hEvent);
            break;
        }
    }
    return 0;
}

int main(void)
{
    HANDLE hThread[2] = { NULL };
    hEvent = CreateEvent(NULL, false, false, NULL); //創建一個匿名事件,當參數bManualReset設置為false時
    hThread[0] = CreateThread(NULL, 0, func1, NULL, 0, NULL);
    cout << "Thread-1 is RUNNING" << endl;
    hThread[1] = CreateThread(NULL, 0, func2, NULL, 0, NULL);
    cout << "Thread-2 is RUNNING" << endl;
    SetEvent(hEvent);
    WaitForMultipleObjects(2, hThread, true, INFINITE); //等待兩個線程運行結束
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);
    CloseHandle(hEvent);
    system("pause");
    return 0;
}
  • bManualReset參數為true
////////////////////////////////
//
// FileName : ThreadEventDemo.cpp
// Creator : PeterZheng
// Date : 2018/9/23 18:00
// Comment : The usage of "CreateEvent"
//
////////////////////////////////

#pragma once

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <windows.h>

using namespace std;

DWORD WINAPI func1(LPVOID lpParam);
DWORD WINAPI func2(LPVOID lpParam);

HANDLE hEvent = NULL;
HANDLE hMutex = NULL;
unsigned int unCount = 0;

DWORD WINAPI func1(LPVOID lpParam)
{
    while (true)
    {
        WaitForSingleObject(hEvent, INFINITE);
        WaitForSingleObject(hMutex, INFINITE); //為互斥體上鎖
        ResetEvent(hEvent); // 重置事件為無信號狀態
        if (unCount < 100)
        {
            unCount++;
            Sleep(10);
            cout << "Count: " << unCount << endl;
            SetEvent(hEvent); // 設置事件為有信號狀態
            ReleaseMutex(hMutex); //互斥體解鎖
        }
        else
        {
            SetEvent(hEvent);
            ReleaseMutex(hMutex);
            break;
        }
    }
    return 0;
}

DWORD WINAPI func2(LPVOID lpParam)
{
    while (true)
    {
        WaitForSingleObject(hEvent, INFINITE);
        WaitForSingleObject(hMutex, INFINITE); //為互斥體上鎖
        ResetEvent(hEvent); // 重置事件為無信號狀態
        if (unCount < 100)
        {
            unCount++;
            Sleep(10);
            cout << "Count: " << unCount << endl;
            SetEvent(hEvent); // 設置事件為有信號狀態
            ReleaseMutex(hMutex);
        }
        else
        {
            SetEvent(hEvent);
            ReleaseMutex(hMutex);
            break;
        }
    }
    return 0;
}

int main(void)
{
    HANDLE hThread[2] = { NULL };
    hEvent = CreateEvent(NULL, true, false, NULL); //創建一個匿名事件,當參數bManualReset設置為true時
    hMutex = CreateMutex(NULL, false, NULL); //創建一個匿名互斥體
    hThread[0] = CreateThread(NULL, 0, func1, NULL, 0, NULL);
    cout << "Thread-1 is RUNNING" << endl;
    hThread[1] = CreateThread(NULL, 0, func2, NULL, 0, NULL);
    cout << "Thread-2 is RUNNING" << endl;
    SetEvent(hEvent); // 設置事件為有信號狀態
    WaitForMultipleObjects(2, hThread, true, INFINITE); //等待兩個線程運行結束
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);
    CloseHandle(hEvent);
    CloseHandle(hMutex);
    system("pause");
    return 0;
}

C++多線程同步技巧(二)--- 事件