通過在上一章的學習,我學會使用GetExitCodeThread()這個函數來判斷一個線程是否還在執行。通過這個函數,我就可以對付“
某個線程必須在某個線程結束後才能運行”的情況。複習一下:
程式片段:
for ( ; ; )
{
int rc;
rc = GetExitCodeThread(hThrd,&exitCode);
if (!rc && exitCode != STILL_ACTIVE)
break;
}使用這個方法,必須持續不斷的調用GetExitCodeThread(),直到其結果不再是STILL_ACTIVE。
書上說這方法不好,很浪費cpu時間.,稱為
忙等待(busy waits)。忙等待cpu幾乎用了所有的可用時間去檢查線程是否結束。必須應有的重視,不然你會發現當包含忙等待的程式運行起來後,其它進行中的程式的反應就很遲鈍了。因為 那麼,我應該怎麼做呢?如何才更有效率呢?
另一種有效率的方法:使用WaitForSingleObject()這個函數來完美的解決問題。完成上面程式片段同樣功能只需一句話:
WaitForSingleObject ( hThrd, INFINITE );若hThrd線程沒有結束時,調用這個函數的程式就會在函數調用點停下來,直到hThrd線程結束時(術語:hThrd被激發)才繼續向下執行。不知道大家會不會有這樣疑問------這個函數不會只是把上面的程式片段封裝了一下吧?它真是很有效率嗎?如果它有效率,它是如何做到的呢?可以告訴大家,WaitForSingleObject()不是上述程式片段的簡單封裝,它真的很有效率(不信,按書上的方法,開啟效能管理器看看),至於它如何做到的,我也有興趣知道(知道告訴我),我只知道這個函數得到了作業系統級的某些底層調度函數的支援。 基本上本章的核心內容就是以上所述了。(至於
WaitForSingleObject()參數及傳回值的說明,查書就行了,毋需多言) 具體的看一個實在的例子,勝過在此長篇大論,下面請看:
//
參考書上例子
//
程式的目的:只用3
個線程,
完成6
件事
int main()
{
HANDLE hThrds[3];
int slot = 0;
For ( int I=1 ; I<=6 ; I++)
{
if( I > 3 )
{//
已經存在3
個線程了
//
等待其中的一個線程線束後,再建立線程做剩餘的事情
//
效率不高,因為線程結束的次序與它們被產生的次序不同
WaitForSingleObject( hThrds[slot] , INFINITE ) ;
CloseHandle ( hThrds[slot] );
}
//
構造線程
hThrds[slot] = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);
if (++slot>2)
slot=0;
}// end for
for ( slot=0; slot<3; slot++)
{
//
等待剩餘的線程結束
WaitForSingleObject( hThrds[slot] , INFINITE ) ;
CloseHandle ( hThrds[slot] );
}// end for
}
上面的這段程式有一個問題,就是效率不是很高;理想的狀況是,一旦有一個線程結束,就立刻產生一個線程補上。仔細讀上面的程式,你會發現它無法實現理想的狀況;因為它假設線程結束的次序會和它們被產生的次序相同。比如,當依序產生了1,2,3線程以後,一定是按1,2,3的次序結束。其實不然,也許2比1更早結束。在這時,上面的程式並不會立刻產生一個線程填補2,而是非要等1結束了,才產生線程。那麼能夠實現理想的狀況嗎?答案是可以,請用
WaitForMultipleObjects() 函數, 這個函數的用法基本上與
WaitForSingleObject()差不多,在這裡我就不舉例說明了。 本章最後還提到了
MsgWaitForMultipleObjects() , 這個函數特點是在訊息到達或線程結束時返回。 我想,只要用會了
WaitForSingleObject()這個函數, 那麼
WaitForMultipleObjects()和
MsgWaitForMultipleObjects()看一下也就會用了(書上舉了兩個小例子來說明,看一下花不了多少時間,不必我在這裡廢話了)。 這一章節的內容大概就是這麼多,總結一下:
*
等待線程結束 [ WaitForSingleObject() ]
*
等待多個線程結束 [ WaitForMultipleObjects() ]
*
等待多個線程結束或訊息到達 [ MsgWaitForMultipleObjects() ]