1. 程式人生 > >執行緒與核心物件的同步

執行緒與核心物件的同步

一、簡介
        互鎖函式家族只能在單值上執行,根本無法使執行緒進入等待狀態;關鍵程式碼段只適用於對單個程序中的執行緒實施同步;我們可以使用核心物件來實現執行緒同步。
二、等待函式
       使用等待函式可以使執行緒進入等待狀態,直到一個特定的核心物件變為已通知狀。
(1)、等待單個事件
         DWORD WaitForSingleObject(
                 HANDLE hObject,    //該函式等待的物件控制代碼
                 DWORD   dwMilliseconds); //等待超時時間
(2)、等待多個事件
         DWORD   WaitForMutipleObjects(
                 DWORD     dwCount,    //需要等待的核心數量
                 CONST HANDLE *phObjects,    //核心物件控制代碼陣列的指標
                 BOOL     fWaitAll,    //是否等待所有物件
                 DWORD     dwMilliseconds); //等待超時時間
         注:
         當fWaitAll為TRUE時:執行緒進入等待狀態,直到所有指定的核心物件都變為已通知狀態。
         當fWaitAll為FALSE時:執行緒進入等待狀態,直到指定核心物件中的任何一個變為已通知狀態。
(3)、等待函式返回值
         WAIT_OBJECT_0: 所等待的物件變為已通知狀態
         WAIT_TIMEOUT: 等待超時
         WAIT_FILED:   出現錯誤
三、事件核心物件
1、基本概念
         事件核心物件是一基本核心物件,他能夠通知一個操作已經完成,與其他核心物件一樣,包含一個使用計數。該計數為BOOL型變數,用於指明該事件是否處於已通知狀態還是未通知狀態。另一計數用於指明該事件是自動重置事件還是人工重置事件。
2、事件的型別
   (1)、自動重置事件
         當自動重置事件得到通知時,等待該事件的執行緒只有一個變為可排程執行緒。
   (2)、人工重置事件
         當人工重置事情得到通知時,等待該事件的所有執行緒均變為可排程執行緒。
    注:
         當使用自動重置事件時,系統只允許一個輔助執行緒變成可排程狀態,我們無法控制系統使哪個執行緒可排程,哪個執行緒等待。
         當人工重置時由程式設計師來決定何時設定事件為已通知狀態或未通知狀態,當自動重置時,當等待的事件發生後,系統自動將事件置為相反的狀態。無需程式設計師呼叫ResetEvent函式。
3、建立事件核心物件
         HANDLE CreateEvent(
                 PSECURITY_ATTRIBUTES   psa,    //安全屬性
                 BOOL       fManualReset, //是否人工重置
                 BOOL       fInitialState, //初始化未已通知還是未通知
                 PCTSTR       pszName); //命名核心物件的名字
4、開啟事件核心物件
         HANDLE OpenEvent(
                 DWORD   fdwAccess,
                 BOOL fInherit,
                 PCTSTR pszName);
5、設定事件物件未已通知狀態
         BOOL SetEvent(
                 HANDLE hEvent);
6、設定事件為未通知狀態
         BOOL ResetEvent(
                 HANDLE hEvent);
四、等待定時器核心物件
1、基本用途
         等待定時器是再某個時間或按規定的間隔時間發出自己的訊號通知的核心物件,通常用來再某個時間執行某個操作。
         等待定時器物件總是再未通知狀態建立,必須呼叫SetWaitableTimer函式來告訴定時器何時成為已通知狀態。
2、建立等待定時器核心物件
         HANDLE CreateWaitableTimer(
                 PSECURITY_ATTRIBUTES   psa,    //安全屬性
                 BOOL       fManualReset, //是人工重置還是自動重置
                 PCTSTR       pszName); //命名核心物件的名稱
3、開啟等待定時器核心物件
         HANDLE OpenWaitableTimer(
                 DWORD   dwDesiredAccess, //訪問屬性
                 BOOL   bInheritHandle, //可繼承性
                 PCTSTR   pszName);   //命名核心物件的名稱
4、設定等待定時器為已通知狀態
         BOOL SetWaitableTimer(
                 HANDLE     hTimer,   //要設定的定時器控制代碼
                 Const LARGE_INTEGER *pDueTime, //第一次報時的時刻
                 LONG      lPeriod,   //報時間隔
                 PTIMERAPCROUTINE pfnCompletionRoutine,   //通常設為NULL
                 PVOID      pvArgToCompletionRoutine, //通常設為NULL
                 BOOL      fResume); //通常設為FALSE
5、撤銷定時器
         BOOL CancelWaitableTimer(
                 HANDLE hTimer); //需撤銷的定時器的控制代碼
簡單例子:
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;

HANDLE g_putApple;
HANDLE g_putBanana;
HANDLE g_eatApple;
HANDLE g_eatBanana;
HANDLE g_dish;
HANDLE m_hmtx;

/******************************************************************
*父親放蘋果,兒子吃蘋果,母親放香蕉,女兒吃香蕉
*在一個時間盤子之中只能放一樣水果,蘋果或香蕉
*****************************************************************/

//放蘋果
UINT WINAPI PutAppleThread(PVOID pvParam)
{
        for(int i = 0; i < 10; i++)
       {
               WaitForSingleObject(g_dish, INFINITE);
                WaitForSingleObject(g_putApple, INFINITE);
               cout << "put apple!/n";
               SetEvent(g_eatApple);
               Sleep(5);
       }
       return 0;
}

//放香蕉
UINT WINAPI PutBananaThread(PVOID pvParam)
{
       for(int i = 0; i < 10; i++)
       {
               WaitForSingleObject(g_dish,INFINITE);
               WaitForSingleObject(g_putBanana, INFINITE);
               cout << "put banana!/n";
               SetEvent(g_eatBanana);
       }
       return 0;
}

//吃蘋果
UINT WINAPI EatAppleThread(PVOID pvParam)
{
       for(int i = 0; i < 10; i++)
       {
               WaitForSingleObject(g_eatApple, INFINITE);
               cout << "eat apple!/n";
               SetEvent(g_putApple);
               SetEvent(g_dish);;
       }
       return 0;
}

//吃香蕉
UINT WINAPI EatBananaThread(PVOID pvParam)
{
       for(int i = 0; i < 10; i++)
       {
               WaitForSingleObject(g_eatBanana, INFINITE);
               cout << "eat banana!/n";
               SetEvent(g_putBanana);
               SetEvent(g_dish);
               Sleep(6);
       }
       return 0;
}


int main()
{
       g_putApple = CreateEvent(NULL, FALSE, TRUE, NULL);
       g_putBanana = CreateEvent(NULL, FALSE, TRUE, NULL);
       g_eatApple = CreateEvent(NULL, FALSE, FALSE, NULL);
       g_eatBanana = CreateEvent(NULL, FALSE, FALSE, NULL);
       g_dish = CreateEvent(NULL, FALSE, TRUE, NULL);
       m_hmtx = CreateMutex(NULL, FALSE, NULL);
       HANDLE hThread[4];
       int x;
       hThread[0] = (HANDLE)_beginthreadex(NULL, 0, PutAppleThread, (void *)&x, 0, NULL);
       hThread[1] = (HANDLE)_beginthreadex(NULL, 0, PutBananaThread, (void *)&x, 0, NULL);
       hThread[2] = (HANDLE)_beginthreadex(NULL, 0, EatAppleThread, (void *)&x, 0, NULL);
       hThread[3] = (HANDLE)_beginthreadex(NULL, 0, EatBananaThread, (void *)&x, 0, NULL);
       char ch;
       cin >> ch;
       return 0;
}