可等待定時器問題:
1. 需要的函數:CreateWaitableTimer,SetWaitableTimer.前者建立一個可等待定時器控制代碼,後者設定等待定時器觸發的條件.我們可以多次調用SetWaitableTimer來重設可等待定時器.重設後之前的定時器將關閉.
2. 主要看兩段代碼:
代碼一:(這段代碼在網上出現的機率是較大的)
[cpp] view plaincopyprint?
- HANDLE hTimer = CreateWaitableTimer( NULL,FALSE,NULL );
-
- LARGE_INTEGER li;
-
- li.QuadPart = 0;
-
-
- if( !SetWaitableTimer( hTimer,&li,1000,NULL,NULL,FALSE ))
-
- {
-
- CloseHandle( hTimer );
-
- return;
-
- }
-
- while ( 1 )
-
- {
-
- //clock_t c_beg = clock();
-
- WaitForSingleObject( hTimer,INFINITE );
-
- //clock_t end = clock() - c_beg;
-
- //cout<<"time:"<<end<<endl;
-
- cout<<"定時器觸發了...\n";
-
- }
-
- CloseHandle(hTimer);
HANDLE hTimer = CreateWaitableTimer( NULL,FALSE,NULL );LARGE_INTEGER li;li.QuadPart = 0;if( !SetWaitableTimer( hTimer,&li,1000,NULL,NULL,FALSE )){CloseHandle( hTimer );return;}while ( 1 ){//clock_t c_beg = clock();WaitForSingleObject( hTimer,INFINITE );//clock_t end = clock() - c_beg;//cout<<"time:"<<end<<endl;cout<<"定時器觸發了...\n";}CloseHandle(hTimer);
通過將上面注釋的代碼放開,我們可以發現:
◆ 前兩個定時器出發過程”不穩定”(即它們所耗費的時間並不是1秒.
◆ 就算是穩定了以後,定時器的差距並不是1s而是1000(毫秒)左右,這就奇怪了.
如果說第二個問題是由於執行clock而產生的誤差的話,那麼第一個問題則沒辦法解釋.(其實對於clock的時間幾乎是可以忽略不計的.)
這樣就引入了核心編程裡面作者的代碼:
代碼二:
[cpp] view plaincopyprint?
- HANDLE hTimer = CreateWaitableTimer( NULL,FALSE,NULL );
-
- LARGE_INTEGER li;
-
- li.QuadPart = 0;
-
-
- if( !SetWaitableTimer( hTimer,&li,1000,NULL,NULL,FALSE ))
-
- {
-
- CloseHandle( hTimer );
-
- return;
-
- }
-
-
- while ( 1 )
-
- {
-
- clock_t c_beg = clock();
-
- SleepEx( 1000,TRUE );//這裡並沒有使用WaitForSingleObject,而是使用SleepEx
-
- clock_t end = clock() - c_beg;
-
- cout<<"time:"<<end<<endl;
-
- }
-
- CloseHandle(hTimer);
HANDLE hTimer = CreateWaitableTimer( NULL,FALSE,NULL );LARGE_INTEGER li;li.QuadPart = 0;if( !SetWaitableTimer( hTimer,&li,1000,NULL,NULL,FALSE )){CloseHandle( hTimer );return;}while ( 1 ){clock_t c_beg = clock();SleepEx( 1000,TRUE );//這裡並沒有使用WaitForSingleObject,而是使用SleepExclock_t end = clock() - c_beg;cout<<"time:"<<end<<endl;}CloseHandle(hTimer);
運行結果發現正常:每次都是1000(毫秒).
從這裡可以間接證明,clock消耗的時間可以忽略不計.
再來看看SleepEx是怎麼定義的.
DWORD WINAPI SleepEx(
DWORD dwMillesconds,
BOOL bAlertable);
這裡主要說明第二個參數的用途:線程是否將自己置為可提醒狀態.(在可提醒I/O中,當I/O完成時,系統將他們添加到線程APC隊列中-回呼函數不會立即被調用.如果我們想讓其被調用需要將這個參數設定為TRUE).
本例並沒有牽涉到這類問題,所以無論FALSE或者TRUE都無所謂.
如果我們只想要定義一個一次性定時器.可以參考如下代碼:
[cpp] view plaincopyprint?
- HANDLE hTimer = NULL;
-
- LARGE_INTEGER liDueTime;
-
- liDueTime.QuadPart = -100000000;//10s
-
- hTimer = CreateWaitableTimer(NULL, TRUE,NULL);
-
- if ( hTimer == NULL ) return;
-
- if (!SetWaitableTimer(hTimer, &liDueTime, 1000, NULL, NULL, 0))
-
- {
-
- CloseHandle(hTimer);
-
- return;
-
- }
-
- clock_t c_beg = clock();
-
- if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0)
-
- {
-
- CloseHandle(hTimer);
-
- return ;
-
- }
-
- else
-
- {
-
- //操作
-
- }
-
- CloseHandle(hTimer);
HANDLE hTimer = NULL;LARGE_INTEGER liDueTime; liDueTime.QuadPart = -100000000;//10shTimer = CreateWaitableTimer(NULL, TRUE,NULL); if ( hTimer == NULL ) return; if (!SetWaitableTimer(hTimer, &liDueTime, 1000, NULL, NULL, 0)) { CloseHandle(hTimer); return;}clock_t c_beg = clock();if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0){CloseHandle(hTimer);return ;}else{//操作}CloseHandle(hTimer);
最後需要說明的一點是APC(非同步呼叫過程)加入定時器中:
[cpp] view plaincopyprint?
- VOID APIENTRY TimerAPCRoutine( PVOID pvArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue)
-
- {
-
- cout<<"high:"<<dwTimerHighValue<<" low"<<dwTimerLowValue<<endl;
-
- }
-
- void main()
-
- {
-
- HANDLE hTimer = CreateWaitableTimer( NULL,FALSE,NULL );
-
- LARGE_INTEGER li;
-
- li.QuadPart = 0;
-
-
- if( !SetWaitableTimer( hTimer,&li,1000,TimerAPCRoutine,NULL,FALSE ))
-
- {
-
- CloseHandle( hTimer );
-
- return;
-
- }
-
-
- while ( 1 )
-
- {
-
- SleepEx( 1000,TRUE );
-
- }
-
- CloseHandle( hTimer );
-
- getchar();
-
- }
VOID APIENTRY TimerAPCRoutine( PVOID pvArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue){cout<<"high:"<<dwTimerHighValue<<" low"<<dwTimerLowValue<<endl;}void main(){HANDLE hTimer = CreateWaitableTimer( NULL,FALSE,NULL );LARGE_INTEGER li;li.QuadPart = 0;if( !SetWaitableTimer( hTimer,&li,1000,TimerAPCRoutine,NULL,FALSE )){CloseHandle( hTimer );return;}while ( 1 ){SleepEx( 1000,TRUE );}CloseHandle( hTimer );getchar();}