1. 程式人生 > >讓執行緒休息的幾種方式

讓執行緒休息的幾種方式

一般來說,讓執行緒休息可以用Sleep和wait...等幾種方式。首先說Sleep();
這種方式就是直接讓執行緒休眠多少時間。例如:Sleep(1000);休息1000毫秒;
把CPU的執行讓給其他的執行緒;但是這種方式如果時間把握的不好會造成很大的浪費。比如取一個檔案的時候,正好有另一個執行緒正在存取這個檔案。你無法確定要休息多長時間,如果是主執行緒,你的程式介面說不定就僵死到哪裡。所以Sleep()一定要有一個預知的固定的時間再用。
還有一種方式就是WaitForSingleObject和WaitForMultipleObjects;
這兩個第一個是等一個訊號,第二個可以等多個訊號。用WaitForSingleObject這種方式可以暫時讓執行緒等待,什麼也不做,直到這個語句有返回值的時候這個執行緒就可以繼續執行了,但是當什麼時候他可以返回值,退出這個等待狀態哪 ?下面我們詳細講解一下;它的原形:
DWORD WaitForSingleObject(
HANDLE hHandle,        // handle to object 這個是你等的那個物件有訊號;
DWORD dwMilliseconds   // time-out interval 這個是你設定要等多長時間這個訊號;
);
dwMilliseconds可以設定具體的時間值如:1000 就是1000毫秒。當過了1000毫秒hHandle還沒有訊號那,他就會返回一個WAIT_TIMEOUT值;
dwMilliseconds設定為 INFINITE ,那麼它就會一直等到hHandle有訊號才返回值。如果一直沒有訊號來,那它就一直等到你關閉程式的那一刻。呵呵;
當在規定的時間內hHandle有訊號了,他會返回一個 WAIT_OBJECT_0 值。我們根據他返回的這些值就可以做出適當的判斷了;下面我們做一個等待10000毫秒,
DWORD dw=WaitForSingleObject(你要等待的訊號,10000); switch(dw)
{
case WAIT_OBJECT_0:      
     {           
      ......這個是在規定的時間內有訊號返回的值;            
      break;      
     }             
case WAIT_TIMEOUT:      
    {            
     ......這個是在超過規定的時間內沒有訊號返回的值;            
     break;      
    }     
case WAIT_FAILED:      
    {        
     ......這個就是當語句發生錯誤的時候返回的值;            
     break;      
    }     
default:      
   {
   }
下面我用一問一答的方式來給大家解釋平常認為很理論的東西,其實很簡單:
1、具體要問要等什麼訊號哪,這個訊號是什麼哪?這個要等的訊號就是我們程式產生的一個控制代碼,而這個控制代碼指向的是一個物件;
2、激發和訊號是什麼關係?其實就是一個物件激發了,它就產生了一個訊號,沒有激發,它當然就沒有訊號。呵呵,不要想的太複雜;激發是系統內部的一個動作,比如你被打了一下,你就疼,打就是一個動作,就像物件被激發一樣;疼就是有訊號了。如果不被打一下怎麼會產生疼這個訊號,所以物件被激發產生了一個訊號。
3、哪些物件可以產生訊號?
什麼情況下這些物件可以被激發產生有訊號?那就是
1、執行緒物件,當執行緒結束的時候會被激發狀態,沒有結束的時候是未激發狀態;
2、程序物件,當程序結束的時候會被激發狀態,沒有技術的時候是未激發狀態;
3、檔案物件,當一個檔案或目錄發生一件特別大的事情,比如:檔案物件產生或刪除一個子目錄,產生、刪除、重新命名一個檔案,目錄及目錄的任何屬性改變,最後寫入時間的改變,任何安全屬性的改變都會激發檔案物件為激發狀態;
4、Console input; 當視窗的輸入緩衝區有資料可用的時候變為激發狀態;
5、Event, SetEvent()可以激發產生訊號,ResetEvent()可以使它無訊號;
6、Mutex ; 當沒有一個執行緒擁有它時,它就處於激發態,一旦一個執行緒擁有它就處於未激發態
7、 Semaphore; 當擁有Semaphore的執行緒的個數大於0就處於激發態,當等於0就處於未激發態;所以WaitForSingleObject可以等一個物件產生訊號而返回;比如當一個執行緒要讀一個檔案,然後這個檔案並不存在,你必須啟動另外一個檔案去下載這個檔案,那在下載執行緒還沒有結束前,你肯定是不
能讀了;所以要等下載完了,下載執行緒結束,你的等待語句也就有訊號了,也就可以讀了:HANDLE hdown; 下載執行緒控制代碼;自己寫下載執行緒;------
hdown=CreateThread(.....);
if(WAIT_OBJECT_0==WaitForSingleObject(hdown,INFINITE))
{
..........這裡就可以寫你要操作這個檔案的語句了;
}
上面那個等待語句會一直等待直到下載執行緒結束,然後hdown變為有訊號狀態,這時程式才從休眠狀態中醒過來進行下面的操作。INFINITE引數是一直等,直到有訊號。
WaitForMultipleObjects和上面的類似,就是可以等多個控制代碼有訊號而已。
DWORD WaitForMultipleObjects(
DWORD nCount,             // number of handles in array這個引數是設定要等幾個控制代碼;
CONST HANDLE *lpHandles, // object-handle array這個引數是一個控制代碼陣列,把要等的控制代碼都放在這個數組裡面;
BOOL bWaitAll,            // wait option 如果是true,是所有的控制代碼有訊號才返回,false是當有任何一個控制代碼有訊號就返回;
DWORD dwMilliseconds      // time-out interval 這個就是設定等待時間的;
);

返回的引數和WaitForSingleObject有一點點差異:

WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount – 1);
為什麼是這樣的哪? 因為是:
當bWaitAll是True的時候正常返回值是 WAIT_OBJECT_0;
當bWaitAll是false的時候正常返回值是nCount-WAIT_OBJECT_0-1 ,也就是有訊號的控制代碼在控制代碼陣列中的索引值

WAIT_TIMEOUT 就是在規定的時間裡沒有達到喚醒的等待語句的條件。比如。
當bWaitAll是false的時候一個控制代碼也沒有訊號;
當bWaitAll是True的時候一個控制代碼也沒有訊號或者不時全部的控制代碼都有訊號;

WAIT_FAILED 就是語句出錯的時候返回的值。

如果是WAIT_FAILED,可以用GetLastError()語句來得到錯誤資訊;

WaitForSingleObject和WaitForMultipleObjects還有一個返回值由於不常用就不細說了那就是

WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount – 1)

WAIT_ABANDONED_0代表什麼意思哪?就是當你等待的任何物件有Mutexes時,就會返回這種值,他也是
代表的是有Mutexes物件被激發的控制代碼所在的控制代碼陣列的索引值。