事件EVENT,WaitForSingleObject(),WaitForMultipleObjecct()和SignalObjectAndWait() 的使用(上)

用戶模式的線程同步機制效率高,如果需要考慮線程同步問題,應該首先考慮用戶模式的線程同步方法。但是,用戶模式的線程同步有限制,對于多個進程之間的線程同步,用戶模式的線程同步方法無能為力。這時,只能考慮使用內核模式。

Windows提供了許多內核對象來實現線程的同步。對于線程同步而言,這些內核對象有兩個非常重要的狀態:“已通知”狀態,“未通知”狀態(也有翻譯為:受信狀態,未受信狀態)。Windows提供了幾種內核對象可以處于已通知狀態和未通知狀態:進程、線程、作業、文件、控制臺輸入/輸出/錯誤流、事件、等待定時器、信號量、互斥對象。


與事件EVENT的配合使用,能夠解決很多同步問題,也可以在數據達到某個狀態時啟動另一個線程的執行,如報警。

EVENT 的幾個函數:

1、CreateEvent和OpenEvent

HANDLE WINAPI CreateEvent(__in          LPSECURITY_ATTRIBUTES lpEventAttributes,    //表示安全控制,一般直接傳入NULL,表示不能被子進程繼承__in          BOOL bManualReset,  //參數確定事件是手動置位還是自動置位,傳入TRUE表示手動置位,傳入FALSE表示自動置位。__in          BOOL bInitialState,  //Event的初始狀態, TRUE為觸發,FALSE未觸發__in          LPCTSTR lpName   //Event object的名字,NULL表示沒名字(without a name)
);
要是CreateEvent創建的事件沒名字  這個函數就沒啥用了,不多做介紹,可查看msn。
HANDLE WINAPI OpenEvent(                   //獲得已經存在的Event的事件句柄__in          DWORD dwDesiredAccess,__in          BOOL bInheritHandle,__in          LPCTSTR lpName       //要打開的事件名字
);

2、SetEvent,觸發事件

BOOL SetEvent(HANDLE hEvent);

3、ResetEvent,使事件狀態設為未觸發,如在創建事件時第二個參數為TRUE手動設置,則需要該函數去恢復事件為未觸發狀態。

BOOL SetEvent(HANDLE hEvent);

4、PulseEvent, 如在創建事件時第二個參數為TRUE手動設置,其功能相當于SetEvent()后立即調用ResetEvent(),最好別用

BOOL PulseEvent(HANDLE hEvent)

5、CloseHandle(),關閉該句柄。

事件是內核對象,事件分為手動置位事件和自動置位事件。事件Event內部它包含一個使用計數(所有內核對象都有),一個布爾值表示是手動置位事件還是自動置位事件,另一個布爾值用來表示事件有無觸發。事件可以由SetEvent()來觸發,由ResetEvent()來設成未觸發。還可以由PulseEvent()來發出一個事件脈沖。


WaitForSingleObject()

在多線程下面,有時候我們會希望等待某一線程完成了再繼續做其他事情,要實現這個目的,可以使用Windows API函數WaitForSingleObject,或者WaitForMultipleObjects。這兩個函數都會等待Object被標為有信號(signaled)時才返回的。
那么,什么是信號呢?
簡單來說,Windows下創建的Object都會被賦予一個狀態量。如果Object被激活了,或者正在使用,那么該Object就是無信號,也就是不可用;另一方面,如果Object可用了,那么它就恢復有信號了。

這兩個函數的優點是它們在等待的過程中會進入一個非常高效沉睡狀態,只占用極少的CPU時間片。(這兩個函數都是在內核狀態下等待內核對象,不切換到用戶模式下,因而效率很高)

1、格式

DWORD WaitForSingleObject( HANDLE hHandle, DWORDdwMilliseconds);

有兩個參數,分別是THandle和Timeout(毫秒單位)。

如果想要等待一條線程,那么你需要指定線程的Handle,以及相應的Timeout時間。當然,如果你想無限等待下去,Timeout參數可以指定系統常量INFINITE。

WaitForSingleObject函數用來檢測hHandle事件的信號狀態,當函數的執行時間超過dwMilliseconds就返回,但如果參數dwMilliseconds為INFINITE時函數將直到相應時間事件變成有信號狀態才返回,否則就一直等待下去,直到WaitForSingleObject有返回值才執行后面的代碼。此外,當dwMilliseconds設置為特殊值0時,測試hHandle核心對象是否被激發,函數立即返回。

2. 使用對象
它可以等待如下幾種類型的對象:

Event(事件),Mutex(互斥量),Semaphore(信號量),Process(進程),Thread(線程),Change notification(變更通知),Console input(控制臺輸入),Job(可以被理解為進程的容器),Memory resource notification(內存資源通知),Waitable timer(等待定時器)

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

WAIT_OBJECT_0:核心對象已被激活WAIT_TIMEOUT:等待超時WAIT_FAILED:出現錯誤,可通過GetLastError得到錯誤代碼

4.示例:

#include <windows.h>  
#include <stdio.h>  
#include <iostream.h>  //聲明函數  創建線程  
DWORD WINAPI FunProc( LPVOID lpParameter);   void main()  
{  HANDLE hThread;  hThread=CreateThread(NULL,0,FunProc,NULL,0,NULL);  DWORD dwRet=WaitForSingleObject(hThread, 1);  if(dwRet==WAIT_OBJECT_0)  {  printf("創建的線程執行結束\n");  }  if(dwRet==WAIT_TIMEOUT)  {  printf("等待超時\n");  }  if(dwRet==WAIT_ABANDONED)  {  printf("Abandoned\n");  }  CloseHandle(hThread);  
}  DWORD WINAPI FunProc( LPVOID lpParameter )  
{     int i=1;  for(; i<1000; i++)  {  printf("%d  ", i);  if(! (i%10))  printf("\n");  }  return 0;  
}

注意:不可以在WaitForSingleObject()之前執行CloseHandle()否則會導致程序出錯!!
官方文檔解釋:
這里寫圖片描述
如果在wait操作仍處于暫掛狀態時關閉此句柄,則函數的行為將不明確。


WaitForMultipleObjecct()

WaitForMultipleObjects是Windows中的一個功能非常強大的函數,幾乎可以等待Windows中的所有的內核對象

函數原型為:

DWORD WaitForMultipleObjects(  DWORD nCount,             // number of handles in the handle array  CONST HANDLE *lpHandles,  // pointer to the object-handle array  BOOL fWaitAll,            // wait flag  DWORD dwMilliseconds      // time-out interval in milliseconds  );  

參數解析:

  • DWORD 就是 Double Word, 每個word為2個字節的長度,DWORD雙字即為4個字節,每個字節是8位。
  • nCount 指定列表中的句柄數量 最大值為MAXIMUM_WAIT_OBJECTS(64)

  • *lpHandles 句柄數組的指針。lpHandles為指定對象句柄組合中的第一個元素 HANDLE類型可以為(EventMutexProcessThreadSemaphore)數組

  • bWaitAll 等待的類型,如果為TRUE,表示除非對象都發出信號,否則就一直等待下去;如果FALSE,表示任何對象發出信號即可
  • dwMilliseconds指定要等候的毫秒數。如設為零,表示立即返回。如指定常數INFINITE,則可根據實際情況無限等待下去

函數的返回值有:

  • WAIT_ABANDONED_0:所有對象都發出消息,而且其中有一個或多個屬于互斥體(一旦擁有它們的進程中止,就會發出信號)
  • WAIT_TIMEOUT:對象保持未發信號的狀態,但規定的等待超時時間已經超過
  • WAIT_OBJECT_0:所有對象都發出信號
  • WAIT_IO_COMPLETION:(僅適用于WaitForMultipleObjectsEx)由于一個I/O完成操作已作好準備執行,所以造成了函數的返回
  • 返回WAIT_FAILED則表示函數執行失敗,會設置GetLastError

bWaitAllFALSE,那么返回結果相似,只是可能還會返回相對于WAIT_ABANDONED_0WAIT_OBJECT_0的一個正偏移量,指出哪個對象是被拋棄還是發出信號。

WAIT_OBJECT_0是微軟定義的一個宏,你就把它看成一個數字就可以了。

例如,WAIT_OBJECT_0 + 5的返回結果意味著列表中的第5個對象發出了信號

如果程序中的nObjectWaitWAIT_OBJECT_0 + 5

int nIndex = nObjectWait - WAIT_OBJECT_0;就是說nIndex =5也就表示第5個對象發出了信號

示例:
當 bWaitAll參數為FALSE可以等待其中之一的事件

HANDLE m_hEvent[2];    //兩事件  m_hEvent[0]=CreateEvent(NULL, FALSE, FALSE, NULL);  
m_hEvent[1]=CreateEvent(NULL, FALSE, FALSE, NULL);  
CreateThread(NULL, 0, MyThreadProc, this, 0, NULL);  
DWORD WINAPI MyThreadProc(LPVOID lpParam)  
{   
while(TRUE)  {  //每次等500毫秒   int nIndex = WaitForMultipleObjects(2, pThis->m_hEvent, FALSE,500);     if (nIndex == WAIT_OBJECT_0 + 1)   {  //第二個事件發生   //ExitThread(0);   //break;    
}   else if (nIndex == WAIT_OBJECT_0) //第一個事件發生    
{   //第一個事件  }    
else if (nIndex == WAIT_TIMEOUT) //超時500毫秒    
{   //超時可作定時用    
}   
}  OutputDebugString("線程結束. /n");  return 0L;} 

當要處理第一個事件時,你只需執行SetEvent(m_hEvent[0]); 即可進入第一個事件的位置

當要執行第二個事件時執行SetEvent(m_hEvent[1]);

當 bWaitAll參數為TRUE等待所有的事件

DWORD WINAPI MyThreadProc(LPVOID lpParam)  
{ while(TRUE)  {  //每次等500毫秒    
int nIndex = WaitForMultipleObjects(2, pThis->m_hEvent, TRUE,500);     if (WAIT_OBJECT_0 + 1<= nIndex <= WAIT_OBJECT_0) //所有事件發生   {   //所有的信號量都有效時(事件都發生)其中之一無效。   }  

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/448259.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/448259.shtml
英文地址,請注明出處:http://en.pswp.cn/news/448259.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

axios 中文文檔、使用說明

以下內容全文轉自 Axios 文檔&#xff1a;https://www.kancloud.cn/yunye/axios/234845 ##Axios Axios 是一個基于 promise 的 HTTP 庫&#xff0c;可以用在瀏覽器和 node.js 中。 Features 從瀏覽器中創建 XMLHttpRequests從 node.js 創建 http 請求支持 Promise API攔截請…

汽車熄火是什么原因?

汽車熄火是什么原因&#xff1f; 近來看見很多車主被車子熄火所困擾&#xff0c;駕校一點通幫助您從以下也許可以找出原因。 1、自動檔車型&#xff1a; 自動檔的車型不會輕易出現熄火的現象&#xff0c;而手動檔的車型由于駕駛水平不高&#xff0c;可能會經常出現熄火的現象。…

數據庫 -- 02

引擎介紹 1.什么是引擎 MySQL中的數據用各種不同的技術存儲在文件&#xff08;或者內存&#xff09;中。這些技術中的每一種技術都使用不同的存儲機制、索引技巧、鎖定水平并且最終提供廣泛的不同的功能和能力。通過選擇不同的技術&…

事件EVENT,WaitForSingleObject(),WaitForMultipleObjecct()和SignalObjectAndWait() 的使用(下)

注意&#xff1a;當WaitForMultipleObjects等待多個內核對象的時候&#xff0c;如果它的bWaitAll 參數設置為false。其返回值減去WAIT_OBJECT_0 就是參數lpHandles數組的序號。如果同時有多個內核對象被觸發&#xff0c;這個函數返回的只是其中序號最小的那個。 如果bWaitAll …

設置 shell 腳本中 echo 顯示內容帶顏色

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 shell腳本中echo顯示內容帶顏色顯示,echo顯示帶顏色&#xff0c;需要使用參數 -e 格式如下&#xff1a; echo -e "\033[字背景顏…

Visual C++ 編譯器選項 /MD、/ML、/MT、/LD

前段時間編譯一個引用自己寫的靜態庫的程序時老是出現鏈接時的多個重定義的錯誤&#xff0c;而自己的代碼明明沒有重定義這些東西&#xff0c;譬如&#xff1a; LIBCMT.lib(_file.obj) : error LNK2005: ___initstdio already defined in libc.lib(_file.obj) LIBCMT.lib(_fi…

Delphi面向對象編程的20條規則

Delphi面向對象編程的20條規則 作者簡介 Marco Cantu是一個知名的Delphi專家&#xff0c;他曾出版過《精通Delphi》系列叢書&#xff0c;《Delphi開發手冊》以及電子書《精通Pascal》(該電子書可在網上免費獲得)。他講授的課題是Delphi基礎和高級開發技巧。你可以通過他…

制動失靈怎么辦?

定義 制動過程中&#xff0c;由于制動器某些零部件的損壞或發生故障&#xff0c;使運動部件(或運動機械)不能保持停止狀態或不能按要求停止運動的現象。 制動失靈的原因 制動失靈的關鍵在于制動系統無法對汽車施加足夠的制動力&#xff0c;包括制動液管路液位不足或進入空氣、制…

OpenDDS用idl生成自定義數據類型時遇到的一個問題

問題&#xff1a;這里會提示LNK2005重復定義的錯誤 解決方案&#xff1a; 解決后&#xff1a;

解決:Connect to xx.xx.xxx.xx :8081 [/xx.xx.xx.xx] failed: Connection refu sed: connect -> [H

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 自行啟動了個 Nenux 服務。想把本地工程推送到 個人私服&#xff0c;執行命令&#xff1a;mvn deploy 報錯&#xff1a; Failed to…

ADOQuery 查詢 刪除 修改 插入

//利用combobox組件查詢數據庫表procedure TForm1.Button1Click(Sender: TObject);beginADOQuery1.Close;ADOQuery1.SQL.Clear;ADOQuery1.SQL.Add(select * from trim(ComboBox2.Text));ADOQuery1.Active:true;end&#xff1b; //查詢記錄procedure TForm1.Button1Click(Sender…

防爆胎,有妙招

對于大多數人來說&#xff0c;買車難,養車更難。許多人擁有了新車&#xff0c;卻沒有足夠的知識去好好保養汽車&#xff0c;這實在是非常可惜。如何做好汽車的保養工作,讓我們的愛車更好的為我們工作&#xff1f;夏天熾熱的天氣&#xff0c;是否讓你為爆胎煩惱不已&#xff1f;…

Qt之QProcess(一)運行cmd命令

Qt提供了QProcess類&#xff0c;QProcess可用于完畢啟動外部程序&#xff0c;并與之交互通信。 一、啟動外部程序的兩種方式&#xff1a; &#xff08;1&#xff09;一體式&#xff1a;void QProcess::start(const QString & program, const QStringList & arguments…

Docker 方式安裝 Nexus 私服

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 從Docker 官方倉庫查找鏡像&#xff1a; docker search nexus 2. 拉取鏡像&#xff1a; docker pull 你選中的鏡像的名字  pull…

shader飛線改進版

項目github地址&#xff1a;https://github.com/ecojust/flyline 前面寫過一個飛線(基于THREE.Line進行的顏色變化)&#xff0c;只是簡單地將可視區片元顏色的alpha通道值設為1.0&#xff0c;不在可視區的設為0.0。效果是這樣的&#xff1a; 做得很粗糙&#xff0c;而且因為線是…

轉向盤失控怎么辦?

定義 轉向失控就是方向盤不管用了&#xff0c;打方向盤&#xff0c;但是前輪不動&#xff0c;不受方向盤控制。 轉向失控的原因 轉向失控可能因為車輛過快、酒駕、疲勞、車況不佳、雨雪路滑等&#xff0c;還有轉向機構中有零部件脫落、損壞、卡滯時&#xff0c;也會使轉向機構突…

Socket網絡編程【獲取本機IP】

//12.3.2//運行環境VS2013//獲取本地IP #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib")void main() { // 調用WSAStarup初始化WINsock庫 WSADATA wsaData; ::WSAStartup( MAKEWORD(2,2), &wsaData);// 存放主機名的…

onresize

1 window.onresize function (ev) { 2 console.log(尺寸發生改變&#xff01;); 3 }; 4 5 window.addEventListener(resize, function (ev) { 6 console.log(尺寸發生改變&#xff01;); 7 }); 1 /*2 當屏幕的寬度>960時&#xff0c;頁面的背景顏色為紅色…

Vuejs:組件 slot 內容分發

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 本文是在官方文檔的基礎上&#xff0c;更加細致的說明&#xff0c;代碼更多更全。 簡單來說&#xff0c;更適合新手閱讀 &#xff08;…

C++獲取本機所有ip地址,可區分類型是有線無線虛擬機還是回環

一個小程序&#xff0c;可以獲取本地所有ip地址&#xff0c;包括有線&#xff0c;無線&#xff0c;虛擬機&#xff0c;環回接口網卡&#xff0c;等。 如圖&#xff0c;一臺機器多個網卡&#xff1a; 程序執行結果&#xff1a; #include"stdio.h" #include"…