事件實現線程同步

1、線程函數聲明

DWORD WINAPI ThreadProc(
LPVOID lpParameter);

 2、創建線程函數

HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, 
DWORD dwStackSize, 
LPTHREAD_START_ROUTINE lpStartAddress, 
LPVOID lpParameter, 
DWORD dwCreationFlags, 
LPDWORD lpThreadId); 
lpThreadAttributes:它被設爲NULL,表示使用缺省值。 
dwStackSize,線程堆棧大小,一般=0,在任何情況下,
Windows根據需要動態延長堆棧的大小。 
lpStartAddress,指向線程函數的指針,
形式:@函數名,函數名稱沒有限制,
但是必須以下列形式聲明: DWORD WINAPI ThreadProc (LPVOID pParam) ,
格式不正確將無法調用成功。
 lpParameter:向線程函數傳遞的參數,是一個指向結構的指針,
不需傳遞參數時,爲NULL。 
dwCreationFlags :線程標誌,可取值如下  
               CREATE_SUSPENDED: 創建一個掛起的線程 
               0 :創建後立即激活。 lpThreadId:保存新線程的id。   
返回值:   函數成功,返回線程句柄;函數失敗返回false。 
3、創建事件對象
 HANDLE CreateEvent(   
   LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全屬性  
 BOOL bManualReset, // 復位方式   
   BOOL bInitialState, // 初始狀態  
 LPCTSTR lpName // 對象名稱   );
lpEventAttributes:如果lpEventAttributes是NULL,事件將獲得一個默認的安全符。  
bManualReset:指定將事件對象創建成手動復原還是自動復原。如果是TRUE,那麼必須用ResetEvent函數來手工將事件的狀態復原到無信號狀態。如果設置爲FALSE,當事件被一個等待線程釋放以後,系統將會自動將事件狀態復原爲無信號狀態。
bInitialState:指定事件對象的初始狀態。如果爲TRUE,初始狀態爲有信號狀態;否則爲無信號狀態。  
lpName:指定事件的對象的名稱,是一個以0結束的字符串指針。名稱的字符格式限定在MAX_PATH之內。名字是對大小寫敏感的。

 

4、WaitForSingleObject函數 

  DWORD WaitForSingleObject(

 

  HANDLE hHandle,

 

  DWORD dwMilliseconds

 

  );

 

參數

  hHandle 對象句柄。可以指定一系列的對象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。

 

  當等待仍在掛起狀態時,句柄被關閉,那麼函數行爲是未定義的。該句柄必須具有 SYNCHRONIZE 訪問權限。

 

  dwMilliseconds [in]定時時間間隔,單位爲milliseconds(毫秒).如果指定一個非零值,函數處於等待狀態直到hHandle 標記的對象被觸發,或者時間到了。如果dwMilliseconds 爲0,對象沒有被觸發信號,函數不會進入一個等待狀態,它總是立即返回。如果dwMilliseconds 爲INFINITE,對象被觸發信號後,函數纔會返回。

返回值

  執行成功,返回值指示出引發函數返回的事件。它可能爲以下值:

 

  

 

  WaitForSingleObject函數用來檢測hHandle事件的信號狀態,在某一線程中調用該函數時,線程暫時掛起,如果在掛起的dwMilliseconds毫秒內,線程所等待的對象變爲有信號狀態,則該函數立即返回;如果超時時間已經到達dwMilliseconds毫秒,但hHandle所指向的對象還沒有變成有信號狀態,函數照樣返回。參數dwMilliseconds有兩個具有特殊意義的值:0和INFINITE。若爲0,則該函數立即返回;若爲INFINITE,則線程一直被掛起,直到hHandle所指向的對象變爲有信號狀態時爲止。

 

  返回值:

 

 

  WAIT_ABANDONED 0x00000080:當hHandle爲mutex時,如果擁有mutex的線程在結束時沒有釋放核心對象會引發此返回值。

 

  WAIT_OBJECT_0 0x00000000 :核心對象已被激活

 

  WAIT_TIMEOUT 0x00000102:等待超時

 

  WAIT_FAILED 0xFFFFFFFF :出現錯誤,可通過GetLastError得到錯誤代碼

 

  在這裏舉個例子:

 

  先創建一個全局Event對象g_event:

 

  CEvent g_event;

 

  在程序中可以通過調用CEvent::SetEvent設置事件爲有信號狀態。

 

  下面是一個線程函數MyThreadPro()

 

  UINT CFlushDlg::MyThreadProc( LPVOID pParam )

 

  {

 

  WaitForSingleObject(g_event,INFINITE);

 

  For(;;)

 

  {

 

  ………….

 

  }

 

  return 0;

 

  }

 

  在這個線程函數中只有設置g_event爲有信號狀態時才執行下面的for循環,因爲g_event是全局變量,所以我們可以在別的線程中通過g_event. SetEvent控制這個線程。

 

  還有一種用法就是我們可以通過WaitForSingleObject函數來間隔的執行一個線程函數的函數體

 

  UINT CFlushDlg::MyThreadProc( LPVOID pParam )

 

  {

 

  while(WaitForSingleObject(g_event,MT_INTERVAL)!=WAIT_OBJECT_0)

 

  {

 

  ………………

 

  }

 

  return 0;

 

  }

 

  在這個線程函數中可以通過設置MT_INTERVAL來控制這個線程的函數體多久執行一次,當事件爲無信號狀態時函數體隔MT_INTERVAL執行一次,當設置事件爲有信號狀態時,線程就執行完畢了。

 

5實例分析

#include <windows.h>//頭文件
#include <iostream.h>

//線程函數聲明
DWORD WINAPI Fun1Proc(
LPVOID lpParameter);

DWORD WINAPI Fun2Proc(
LPVOID lpParameter);

 

//全局變量

int tickets=100;
HANDLE g_hEvent;

 

void main()
{
 HANDLE hThread1;
 HANDLE hThread2;

 

//創建事件,NULL默認安全性;FALSE自動重置事件對象,當線程等到該事件的所有權後,系統自動將該對象設爲無信號狀態;TRUE初始有信號;NULL無名事件

 g_hEvent=CreateEvent(NULL,FALSE,TRUE,NULL);

 hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);//創建線程
 hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
   
 CloseHandle(hThread1);//關閉線程
 CloseHandle(hThread2);

 

 Sleep(4000);//延時4s

 

 CloseHandle(g_hEvent);//關閉事件
}

 

//線程函數實現

DWORD WINAPI Fun1Proc(
LPVOID lpParameter)
{
 while(TRUE)
 {
  WaitForSingleObject(g_hEvent,INFINITE);//等待事件

  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread1 sell ticket : "<<tickets--<<endl;
   SetEvent(g_hEvent);//設置事件有信號
  }
  else
  {
   SetEvent(g_hEvent);
   break;
  }
 }
 return 0;
}

DWORD WINAPI Fun2Proc(
LPVOID lpParameter)
{
 while(TRUE)
 {
  WaitForSingleObject(g_hEvent,INFINITE);

  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread2 sell ticket : "<<tickets--<<endl;
   SetEvent(g_hEvent);
  }
  else
  {
   SetEvent(g_hEvent);
   break;
  }
 }
 return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章