---------------------本文分2部分 第1部分:講解 第2部分:轉載---------------------
------------------------------------------第1部分:講解------------------------------------------
聯(lián)系:都是等待
區別:視不同場(chǎng)合,各有優(yōu)勢.另外,有點(diǎn),就是wait系列函數在使用時(shí),占用電腦資源最少,
舉例:
如果在同一臺電腦上,你寫(xiě)了一個(gè)服務(wù)器與客戶(hù)端,你希望服務(wù)端先開(kāi)啟,客戶(hù)端遲些開(kāi)啟,就可以用sleep.
sleep還有一個(gè)功能,就是sleep(0),表示調用線(xiàn)程將釋放剩余的時(shí)間片,并迫使系統調度另一個(gè)線(xiàn)程,
如果你編寫(xiě)了一個(gè)程序,你想實(shí)現一個(gè)等待,但是此時(shí)界面線(xiàn)程已退出了,雖然工作線(xiàn)程開(kāi)啟了,
你可能會(huì )想,在程序中判斷工作線(xiàn)程什么時(shí)候退出,用while(1)之類(lèi),但是很明顯的這種方案很不通,
第1,目標不明確,比如寫(xiě)完成端口時(shí),監聽(tīng)工作線(xiàn)程是可變動(dòng)的,里面有個(gè)線(xiàn)程池,會(huì )檢測監聽(tīng)線(xiàn)程的處理能力,如果網(wǎng)絡(luò )高峰期,就會(huì )動(dòng)態(tài)增添監聽(tīng)線(xiàn)程,此時(shí)原有1個(gè)監聽(tīng)線(xiàn)程變成了2個(gè)
第2.占用資源高,while資源是最高的,它是從不休息的,也不會(huì )把CPU時(shí)間片使用權讓給別的線(xiàn)程
第3.讓線(xiàn)程擁有了阻塞權限,很明顯用while后,就卡在那了
------------------------------------------第2部分:轉載------------------------------------------
---------------------->轉載1
VOID Sleep(DWORD dwMilliseconds); 該函數可使線(xiàn)程暫停自己的運行,直到dwMilliseconds過(guò)去為止。
關(guān)于Sleep函數,有下面幾個(gè)重要問(wèn)題值得注意:
* 調用Sleep,可使線(xiàn)程自愿放棄它剩余的時(shí)間片。
* 系統將在大約的指定毫秒數內使線(xiàn)程不可調度。
* 你可以調用Sleep,并且為dwMilliseconds參數傳遞INFINITE。這將告訴系統永遠不要調度該線(xiàn)程。這不是一件值得去做的事情。最好是讓線(xiàn)程退出,并還原它的堆棧和內核對象。
* 你可以將0傳遞給Sleep。這將告訴系統,調用線(xiàn)程將釋放剩余的時(shí)間片,并迫使系統調度另一個(gè)線(xiàn)程。但是,系統可以對剛剛調用Sleep的線(xiàn)程重新調度。如果不存在多個(gè)擁有相同優(yōu)先級的可調度線(xiàn)程,就會(huì )出現這種情況。
等待函數可使線(xiàn)程自愿進(jìn)入等待狀態(tài),直到一個(gè)特定的內核對象變?yōu)橐淹ㄖ獱顟B(tài)為止。這些等待函數中最常用的是WaitForSingleObject 和WaitForMultipleObjects。
WaitForSingleObject函數:
DWORD WaitForSingleObject(HANDLE hObject, // 等待的核心對象
DWORD dwTimeout ) ; // 線(xiàn)程愿意等待的毫秒數(值為INFINITE時(shí)表示無(wú)限等待)
返回值:
返回值 定義 含義
WAIT_OBJECT_0 0x00000000 對象達到有信號
WAIT_TIMEOUT 0x00000102 對象沒(méi)有在dwTimeout毫秒內 到達有信號狀態(tài)
WAIT_ABANDONED 0x00000080 對象是一個(gè)互斥量,由于它被放棄了而達到有信號狀態(tài)
WAIT_FAILED 0xFFFFFFFF 發(fā)生錯誤。調用GetLastError以取得擴展的錯誤信息
WaitForMultipleObject函數:
DWORD WaitForMultipleObject(DWORD cObject, // 檢查核心對象的數目
LPHANDLE lpHandles, // 指向這些對象的句柄的數組
BOOL bWaitAll, // 是否等待所有對象變成有信號
DWORD dwTimeout); // 線(xiàn)程愿意等待的時(shí)間(毫秒數)
返回值:
返回值 定義 含義
WAIT_OBJECT_0到
(WAIT_OBJECT_0+cObjects-1) 0x00000000 開(kāi)始當等待所有對象時(shí),這一值表明等待對象成功的完成了。當等待任一對象
時(shí),這一值給出 lpHandles數組中屬于變成有信號的對象的下標。
WAIT_TIMEOUT 0x00000102 對象或對象們沒(méi)有在dwTimeout毫秒內達到有信號狀態(tài)。
WAIT_ABANDONED_0到
(WAIT_ABANDONED_0+cObjects-1)
開(kāi)始于0x00000080 當等待所有對象時(shí),這一值指明WAIT_ABANDONED_0等待成功的完成,并且至少有一個(gè)對象是互斥量,此互斥量是由于被放棄而達到有信號的。當等待任一對象時(shí),這一值給出lpHandles數組中屬于變得有信號的互斥量的句柄的下標,此互斥量由于被放棄而達到有信號。
WAIT_FAILED 0xFFFFFFFF 發(fā)生錯誤。 調用GetLastError以取得擴展的錯誤信息。
該文章轉載自無(wú)憂(yōu)考網(wǎng):http://www.51test.net/show/312914.html?#JUMP
---------------------->轉載2
線(xiàn)程同步之WaitForSingleObject及WaitForMultipleObjects
2008-09-18 09:03
線(xiàn)程同步之WaitForSingleObject及WaitForMultipleObjects 前言:看過(guò)win 核心編程的應該都知道,擁護方式的線(xiàn)程同步機 制具有局限性,無(wú)法使線(xiàn)城進(jìn)入等待狀態(tài),當然可以使用關(guān)鍵代碼段 讓線(xiàn)程進(jìn)入等待狀態(tài),但這樣容易陷入死鎖,因為在等待進(jìn)入關(guān)鍵代 碼段時(shí)無(wú)法設定超時(shí)值。 大多數應用程序使用的是內核對象來(lái)實(shí)現線(xiàn)程同步,使用這個(gè)機 制時(shí)調用者線(xiàn)程必須從用戶(hù)方式轉為kernel模式。所以運行會(huì )比較緩 慢,但是穩定。 一。內核對象來(lái)實(shí)現線(xiàn)程同步的原理: 進(jìn)程內核對象總是在未通知狀態(tài)(FALSE)中創(chuàng )建的,當進(jìn)程正 在運行的時(shí)候,進(jìn)程內核對象處于未通知狀態(tài)(FALSE),當進(jìn)程終 止運行的時(shí)候,它就變?yōu)橐淹ㄖ獱顟B(tài)(TURE)。同理,線(xiàn)程內核對象 也是這樣。通過(guò)調用線(xiàn)程等待某個(gè)內核對象變?yōu)橐淹ㄖ獱顟B(tài)所用的函 數,就可以實(shí)現線(xiàn)程同步。 二。函數說(shuō)明: DWORD WaitForSingleObject(HANDLE hObject,DWORD dwMilliseconds); 線(xiàn)程調用該函數時(shí),第一個(gè)參數h O b j e c t標識一個(gè)能夠支持 被通知/未通知的內核對象,第二個(gè)參數d w M i l l i s e c o n d s允許該線(xiàn)程指明,為了等待該對象變?yōu)橐淹ㄖ獱顟B(tài),它將等待多長(cháng) 時(shí)間。 調用下面這個(gè)函數將告訴系統,調用函數準備等待到h P r o c e s s句柄標識的進(jìn)程終止運行為止: WaitForSingleObject(hProcess, INFINITE); 傳遞INFINITE表示調用線(xiàn)程愿意永遠等待下去(無(wú)限時(shí)間量), 直到hProcess標識的進(jìn)程終止運行。 函數返回植: 返回值指明調用線(xiàn)程為什么再次變?yōu)榭烧{度狀態(tài)。。如果線(xiàn)程等 待的對象變?yōu)橐淹ㄖ獱顟B(tài),那么返回值是WA I T _ O B J E C T _ 0 。 如果設置的超時(shí)已經(jīng)到期(假如傳遞的參數是5000ms),則返回值是 WA I T _ T I M E O U T。如果將一個(gè)錯誤的值(如一個(gè)無(wú)效句柄) 傳遞給Wa i t F o r S i n g l eO b j e c t,那么返回值將是 WA I T _ FA I L E D。 DWORD dw = WaitForSingleObject(hProcess, 5000); switch(dw) { case WAIT_OBJECT_0: // 進(jìn)程終止 break; case WAIT_TIMEOUT: // 進(jìn)程在 5000 ms 內沒(méi)有被終止 break; case WAIT_FAILED: // 傳遞的是錯誤的句并 break; } 三。函數說(shuō)明:
DWORD WaitForMultipleObjects(DWORD dwCount, CONST HANDLE* phObjects, BOOL fWaitAll, DWORD dwMilliseconds); 與Wa i t F o r S i n g l e O b j e c t函數很相似,區別在于它允許調用線(xiàn)程同時(shí)查看若干個(gè)內核對象的已通知狀態(tài)。 d w C o u n t參數用于指明想要讓函數查看的內核對象的數量,其植在0—64之間。 *********************************************注意:WaitForMultipleObjects上限是64個(gè)********************************************* 注意:當用多線(xiàn)程時(shí),用這個(gè)會(huì )很方便,但是它有個(gè)上限,就是64,超過(guò)這個(gè)值后,此函數就會(huì )返回錯誤 ******************************************************************************************************************************************** p h O b j e c t s參數是指向 內核對象句柄的數組的指針。f Wa i t A l l參數可為FA L S E或TURE,如傳遞的是FALSE,那么只要有任何一個(gè)對象變?yōu)橐淹ㄖ獱?/p> 態(tài),該函數便返回,如果傳遞的是TURE,必須等到數組中所以句并標識的對象全部變?yōu)橐淹ㄖ欧祷亍?/p> 代碼示例: HANDLE h[3]; h[0] = hProcess1; h[1] = hProcess2; h[2] = hProcess3; DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000); switch(dw) { case WAIT_FAILED: // 非法句并 break; case WAIT_TIMEOUT: // 超時(shí) break; case WAIT_OBJECT_0 + 0: // h[0] 標識的進(jìn)程終止 break; case WAIT_OBJECT_0 + 1: // h[1] 標識的進(jìn)程終止 break; case WAIT_OBJECT_0 + 2: // h[3] 標識的進(jìn)程終止 break; } 需要注意的是:如果數組中索引為0的進(jìn)程終止運行, 這時(shí)該線(xiàn)程就可以做它需要的任何事情,然后循環(huán)反復, 等待另一個(gè)進(jìn)程終止運行。如果該線(xiàn)程傳遞相同的3個(gè)句柄, 該函數立即再次返回WA I T _ O B J E C T _ 0。 除非刪除已經(jīng)收到通知的句柄,否則代碼就無(wú)法正確地運行。 |
---------------------->轉載3
在多線(xiàn)程下面,有時(shí)候我們會(huì )希望等待某一線(xiàn)程完成了再繼續做其他事情,要實(shí)現這個(gè)目的,可以使用Windows API函數WaitForSingleObject,或者WaitForMultipleObjects
這兩個(gè)函數都會(huì )等待Object被標為有信號(signaled)時(shí)才返回的
那么,什么是信號呢?
簡(jiǎn)單來(lái)說(shuō),Windows下創(chuàng )建的Object都會(huì )被賦予一個(gè)狀態(tài)量。如果Object被激活了,或者正在使用,那么該Object就是無(wú)信號,也就是不可用;另一方面,如果Object可用了,那么它就恢復有信號了。
這兩個(gè)函數的優(yōu)點(diǎn)是它們在等待的過(guò)程中會(huì )進(jìn)入一個(gè)非常高效沉睡狀態(tài),只占用極少的CPU時(shí)間片
WaitForSingleObject有兩個(gè)參數,分別是THandle和Timeout(毫秒單位)。如果想要等待一條線(xiàn)程,那么你需要指定線(xiàn)程的Handle,以及相應的Timeout時(shí)間。當然,如果你想無(wú)限等待下去,Timeout參數可以指定系統常量INFINITE。例如:
WaitForSingleObject(aThread.Handle, INFINITE);
相對來(lái)說(shuō),WaitForMultipleObjects要復雜點(diǎn)點(diǎn),它有四個(gè)參數,分別是
1. cObject,DWORD類(lèi)型,用于指定句柄數組的數量
2. lphObjects,Pointer類(lèi)型,用于指定句柄數組的內存地址
3. fWaitAll,Boolean類(lèi)型,True表示函數等待所有指定句柄的Object有信號為止
4. dwTimeout,DWORD類(lèi)型,用于指定等待的Timeout時(shí)間,單位毫秒,可以是INFINITE
如果需要在一個(gè)線(xiàn)程中等待多個(gè)事件,則用WaitForMultipleObjects()來(lái)等待。WaitForMultipleObjects()與WaitForSingleObject()類(lèi)似,
同時(shí)監視位于句柄數組中的所有句柄。這些被監視對象的句柄享有平等的優(yōu)先權,任何一個(gè)句柄都不可能比其他句柄具有更高的優(yōu)先權。
WaitForMultipleObjects()的函數原型為:
DWORD WaitForMultipleObjects(
DWORD nCount, // 等待句柄數
CONST HANDLE *lpHandles, // 句柄數組首地址
BOOL fWaitAll, // 等待標志
DWORD dwMilliseconds // 等待時(shí)間間隔
);
參數nCount指定了要等待的內核對象的數目,存放這些內核對象的數組由lpHandles來(lái)指向。fWaitAll對指定的這nCount個(gè)內核對象的兩種等待方式
進(jìn)行了指定,為T(mén)RUE時(shí)當所有對象都被通知時(shí)函數才會(huì )返回,為FALSE則只要其中任何一個(gè)得到通知就可以返回。dwMilliseconds在這里的作用與
在WaitForSingleObject()中的作用是完全一致的。如果等待超時(shí),函數將返回WAIT_TIMEOUT。如果返回WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1中的某個(gè)
值,則說(shuō)明所有指定對象的狀態(tài)均為已通知狀態(tài)(當fWaitAll為T(mén)RUE時(shí))或是用以減去WAIT_OBJECT_0而得到發(fā)生通知的對象的索引(當fWaitAll為FALSE時(shí))。
如果返回值在WAIT_ABANDONED_0與WAIT_ABANDONED_0+nCount-1之間,則表示所有指定對象的狀態(tài)均為已通知,且其中至少有一個(gè)對象是被丟棄的互斥對象
(當fWaitAll為T(mén)RUE時(shí)),或是用以減去WAIT_OBJECT_0表示一個(gè)等待正常結束的互斥對象的索引(當fWaitAll為FALSE時(shí))。
另一篇文章介紹:
Windows Via C/C++:內核模式下的線(xiàn)程同步——WaitForSingleObject/WaitForMultipleObjects函數 收藏
Wait函數族會(huì )使當前線(xiàn)程進(jìn)入等待狀態(tài),直到指定的內核對象狀態(tài)變?yōu)閟ignaled或等待超時(shí)時(shí)才被重新調度。如果在調用WaitXXX時(shí)指定的內核對象狀態(tài)已是signaled,則 WaitXXX馬上返回。迄今為止,最常用的Wait函數便是WaitForSingleObject:
DWORD WaitForSingleObject( HANDLE hObject, DWORD dwMilliseconds); 首參數hObject指定了當前線(xiàn)程要等待的內核對象,參數dwMilliseconds指定了當前線(xiàn)程等待hObject變成signaled狀態(tài)的最長(cháng)等待時(shí)間,取INFINITE時(shí)表示無(wú)時(shí)間限制。下面是使用WaitForSingleObject的例子:
DWORD dw = WaitForSingleObject(hProcess, 5000); switch(dw){ case WAIT_OBJECT_0: // the process hProcess terminated and becomes signaled break; case WAIT_TIMEOUT: // the process did not terminate within 5000 milliseconds break; caes WAIT_FAILED: // bad call to function (invalid handle?) break; } WaitForSingleObject的返回值表明了當前線(xiàn)程重新被調度的原因。WAIT_OBJECT_0表示等待的內核對象狀態(tài)已變?yōu)閟ignaled,WAIT_TIMEOUT表示等待超時(shí),假如傳遞給WaitForSingleObject的參數有誤時(shí),函數返回WAIT_FAILED。
線(xiàn)程可以調用函數WaitForMultipleObjects同時(shí)等待多個(gè)內核對象的狀態(tài)變?yōu)閟ignaled:
DWORD WaitForMultipleObjects( DWORD dwCount, CONST HANDLE* phObjects, BOOL bWaitAll, DWORD dwMilliseconds); 參數dwCount表示要等待的內核對象的數目,該值必須位于1和MAXIMUM_WAIT_OBJECTS(在WinNT.h中定義為64)之間。phObjects指向要等待對象的句柄數組,其元素個(gè)數為dwCount。參數bWaitAll為T(mén)RUE時(shí),函數將等待phObjects中所有的對象狀態(tài)變?yōu)閟ignaled或超時(shí)后返回,取 FALSE時(shí),函數將在phObjects中任一對象狀態(tài)變?yōu)閟ignaled或超時(shí)后返回。dwMilliseconds設置函數等待的超時(shí)時(shí)間。
WaitForMultipleObjects可能的返回值如下所示:
參數有誤時(shí)返回WAIT_FAILED 待待超時(shí)時(shí)返回WAIT_TIMEOUT 當參數bWaitAll為T(mén)RUE,且phObjects中的所有對象狀態(tài)在dwMilliseconds時(shí)間內變?yōu)閟ignaled時(shí),函數返回WAIT_OBJECT_0 當參數bWaitAll為FALSE,且phObjects中某一對象的狀態(tài)在dwMilliseconds時(shí)間內變成signaled時(shí),函數返回,且返回值減去WAIT_OBJECT_0之后,便得到變?yōu)閟ignaled的對象在phObjects中的索引。 下面我們舉例說(shuō)明WaitForMultipleObjects的用法:
HANDLE h[3]; h[0] = hProcess1; h[1] = hProcess2; h[2] = hProcess3; DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000); switch(dw){ case WAIT_FAILED: // Bad call to function (invalid handle?) break; case WAIT_TIMEOUT: // None of the objects became signaled within 5000 milliseconds break; case WAIT_OBJECT_0: // The process identified by h[0] (hProcess 1) terminated break; case WAIT_OBJECT_0+1: // The process identified by h[1] (hProcess 2) terminated break; case WAIT_OBJECT_0+2: // The process identified by h[2] (hProcess 3) terminated break; } -------------------------------------------另附源代碼WaitForSingleObject
---->專(zhuān)門(mén)的任務(wù)事件對象(服務(wù)端)
// 創(chuàng )建事件對象,在所有下載完成后,發(fā)送一個(gè)下載完成的事件通知,退出程序
HANDLE hEvent = ::CreateEvent(NULL, FALSE, FALSE, _T("ShutdownEvent"));
::WaitForSingleObject(hEvent, INFINITE);
::CloseHandle(hEvent);
---->專(zhuān)門(mén)的任務(wù)事件對象(客戶(hù)端)
HANDLE hEvent = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, "ShutdownEvent");//詳見(jiàn)備注4
if(hEvent != NULL)
{
::SetEvent(hEvent);//詳見(jiàn)備注5
::CloseHandle(hEvent);//詳見(jiàn)備注3
::MessageBox(NULL, " 服務(wù)器關(guān)閉成功!\n", "ServerShutdown", 0);
}
else
{
::MessageBox(NULL, " 服務(wù)器還沒(méi)有啟動(dòng)!\n", "ServerShutdown", 0);
}
-------------------------------------------另附源代碼WaitForMultipleObjects
#include "stdafx.h"
#include <Windows.h>
/*//或者不用#include <Windows.h>
#include<iostream>
using namespace std;
#include "winsock2.h"
#pragma comment(lib, "WS2_32") //為確保安全,最好包含進(jìn)去
*/
HANDLE h1Event = ::CreateEvent(NULL, FALSE, FALSE, NULL);
HANDLE h2Event = ::CreateEvent(NULL, FALSE, FALSE, NULL);
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hWaitEvents[2];
hWaitEvents[0]=h1Event;
hWaitEvents[1]=h2Event;
WaitForMultipleObjects(2, hWaitEvents, TRUE, INFINITE);//參數1,代表等待幾個(gè)線(xiàn)程 參數3,表示等所有線(xiàn)程完成后才退出 參數4,表示無(wú)限制時(shí)間
printf("所有線(xiàn)程都下載完成,現已退出!");
return 0;
}
/*
//另外有種使用方法是&hWaitEvents[2],表示引用的位置從第3個(gè)位置開(kāi)始,
//注:下面的指針數組,前2個(gè)指向CreateEvent創(chuàng )建事件(可用上面例子使用),后2個(gè)指向CreateThread線(xiàn)程.若需要指定的,可以使用此方法
// 等待I/O處理線(xiàn)程退出
::WaitForMultipleObjects(MAX_THREAD, &hWaitEvents[2], TRUE, 5*1000);//注意此處是從線(xiàn)程開(kāi)始計數
for(int i=2; i<MAX_THREAD + 2; i++)
{
::CloseHandle(hWaitEvents[i]);
}
*/
----------------------
附注1:視情況而定