1. 程式人生 > >windows多線程(七) 事件event

windows多線程(七) 事件event

繼承性 image pre 說明 無法 cal urn dac window

前面說的互斥量Mutex與關鍵段CriticalSection都不能實現線程的同步,只能實現互斥,接下來我們用時間event就可以實現線程的同步了,事件也是一個內核對象。

一、相關函數說明

(一) 創建事件
1.函數原型

HANDLE WINAPI CreateEventW(
                _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,
                _In_ BOOL bManualReset,
                _In_ BOOL bInitialState,
                _In_opt_ LPCWSTR lpName
                );
2.參數說明
  • 第一個參數表示安全控制,一般直接傳入NULL。

  • 第二個參數確定事件是手動置位還是自動置位,傳入TRUE表示手動置位,傳入FALSE表示自動置位。如果為自動置位,則對該事件調用WaitForSingleObject()後會自動調用ResetEvent()使事件變成未觸發狀態。

  • 第三個參數表示事件的初始狀態,傳入TRUR表示已觸發。

  • 第四個參數表示事件的名稱,傳入NULL表示匿名事件。

(二) 打開事件
1.函數原型

HANDLE WINAPI OpenEventW(
                _In_ DWORD dwDesiredAccess,
                _In_ BOOL bInheritHandle,
                _In_ LPCWSTR lpName
                );
2.參數說明
  • 第一個參數表示訪問權限,對事件一般傳入EVENT_ALL_ACCESS。

  • 第二個參數表示事件句柄繼承性,一般傳入TRUE即可。

  • 第三個參數表示名稱,不同進程中的各線程可以通過名稱來確保它們訪問同一個事件。

(三) 觸發事件
1.函數原型

BOOL WINAPI SetEvent(
              _In_ HANDLE hEvent
            );
2.參數說明
  • 函數說明:每次觸發後,必有一個或多個處於等待狀態下的線程變成可調度狀態。

  • hEvent 為要觸發的事件的句柄(內核對象)

(四)、 將事件設為末觸發
1.函數原型

BOOL WINAPI ResetEvent(
              _In_ HANDLE hEvent
            );
2.參數說明
  • hEvent 為要觸發的事件的句柄(內核對象)

二、實例

前面我們用關鍵段和互斥量無法實現線程同步,在前面的程序中,我們可以實現對全局資源互斥訪問,即每個線程給全局資源加一,現在使用事件可以時間線程同步,即實現每個線程按順序依次給全局資源加一,代碼如下:



//使用事件進行線程同步

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

using namespace std;

CRITICAL_SECTION g_csVar;
HANDLE g_event;
const int THREAD_NUM = 10;
int g_Num = 0;

DWORD WINAPI  Func(LPVOID);


int main()
{
    g_event = CreateEvent(NULL, false, false, NULL);    //初始化事件為未觸發狀態
    InitializeCriticalSection(&g_csVar);
    DWORD  ThreadId[THREAD_NUM];
    HANDLE handle[THREAD_NUM];
    int i = 0;
    while (i < THREAD_NUM)
    {
        handle[i] = CreateThread(NULL, 0, Func, &i, 0, &ThreadId[i]);
        WaitForSingleObject(g_event, INFINITE); //等待事件被觸發
        i++;
    }
    WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);

    CloseHandle(g_event);
    DeleteCriticalSection(&g_csVar);
    return 0;
}


DWORD WINAPI Func(LPVOID p)
{
    int nThreadNum = *(int*)p;
    
    EnterCriticalSection(&g_csVar);
    cout << "線程編號為:" << nThreadNum << " 給全局資源g_Num 加1,現在給全局資源g_Num值為:" << ++g_Num << endl;
    LeaveCriticalSection(&g_csVar);
    SetEvent(g_event);  //觸發事件
    return 0;
}

運行結果如下所示:

技術分享圖片

windows多線程(七) 事件event