定時器和多線程的不同

C++ SetTimer    多媒體計時器和多線程計時器的使用   SetTimer的使用

軟件定時器和多線程在控制工程中有着非常廣泛的使用,主要是因爲在控制過程中,會出現大量的Socket通信和串口通信數據量,仔細想了想,覺得這兩樣東西還是有比較的價值的,很多初學者(我也是。。。)可能會在這兩樣東西上困惑,現簡單比較一下。

       首先注意: 線程消息隊列中WM_PAINT,WM_TIMER只有在Queue中沒有其他消息的時候纔會被處理,WM_PAINT消息還會被合併以提高效率。其他所有消息以先進先出(FIFO)的方式被處理。http://zhidao.baidu.com/question/176892832.html?fr=ala0

1 軟件定時器

很多同學在工程中喜歡使用軟件定時器,因爲其使用簡單,僅需設置一個時長和其OnTime事件即可使用。確實,軟件定時器在某些持續性不強的重複性工作中效率還是不錯的,但是也有着很大的缺點。

缺點1,速度:軟件定時器的精度比較低,這是由Windows不實時的特性所決定的,在XP下,如果關閉所有能關閉的進程,MFC的軟件定時器可以達到接近15ms的精度,而在Win2000下,其能達到接近10ms的精度。但是實際情況是,有些進程是不可以關閉的,比如說數據庫服務器,所以MFC的軟件定時器能夠達到的精度一般情況下在40ms左右,BCB和delphi就更差一點,大概在55ms左右。QueryPerformanceCounter倒是可以大幅提高精度,但是穩定性欠佳。

缺點2,效率:軟件定時器其本質實際上是在消息循環中處理WM_TIMER消息,而WM_TIMER消息在消息隊列中是一個低級別的消息,所以定時器並不能完全保證處理時間間隔的準確性。另外,Timer佔用的是主線程的資源,看似並行實際上是串行,所以窗體的消息隊列一旦堵塞,就會造成系統假死或者運行緩慢,這對於UI來說幾乎是無法忍受的。

2 多線程

多線程技術是在控制工程中常用的技術,因爲在閉環系統中有着大量的數據處理,這些處理顯然不可能放在主線程中處理,絕大多數都是在線程中使用。多線程的優點比較明顯,就是把費勁的東西扔到後臺去,而且對CPU的利用率比較高。如果控制的好,多線程幾乎是沒有什麼缺點的,但實際上控制的好的並不多……原因如下:

1、時間片不可控,搶CPU資源的事情~一般人說不清;

2、同步比較複雜,容易發生死鎖,3條線程同步一般就能把人折騰死。同步我比較喜歡用臨界區,原因也很簡單:因爲臨界區比較簡單……

http://cache.baidu.com/c?m=9f65cb4a8c8507ed4fece7631046893b4c4380146d96864968d4e414c422461e4d6ce4be2329171980852d3d5aeb1e41eaf235702a0125aa99cd954dd8b8992e2a883034074fc70358c75cf28b102ad650944d9aa50e96c9e74290b9d3a3c82557dd27006d81809c2a7303bb19e71541f4d7ed5f632b07caec27148e4e7659885347a136fff7331e10f0f3ca2846d45ad3766595&p=8b2a9204809b1fb906bd9b7f0d57&user=baidu

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

1.軟件開發當中經常需要用到這兩個好東東,但是兩個使用起來是有很大區別的哦,
  如果在PC上可能效果差不多,如果放到CE小手持設備可能就很明顯的感覺得到;
  如果是定時器,如果是在有界面處理的APP中,你會感覺到程序在一頓一頓的;
  當然,如果處理的東西本來就很少很少,用兩者是沒有感覺的,但是用在很大的
  耗時處理上面,效果就出來了;
  爲什麼呢?因爲Timer來了優先級很高所以會先去處理定時器例程,如果處理很
  耗時,那一定會一頓一頓的;
  Thread就不同了,CE也是搶佔式OS,多線程時是時間輪片處理的;所以如果用線程
  的話也可以達到定時器的效果,並且不會感覺到一頓一頓的BUG;因爲無論你的處理
  有多耗時,時間片一到就又去處理別的了;如果處理的內容很獨立,沒有與其他
  線程有耦合的話,是可以這樣做的;

2.

 

 SetTimer函數和WM_TIMER消息是Win32 api中最基本的玩意兒了,任何初學Win32 api編程的人都應該對此很熟悉吧。在這篇文章中,讓我們來深入瞭解一下和SetTimer相關的使用和應用。

  UINT_PTR SetTimer(

  HWND hWnd,

  UINT_PTR nIDEvent,

  UINT uElapse,

  TIMERPROC lpTimerFunc

  );

  我們經常使用的情況是hWnd不爲NULL,lpTimerFunc爲NULL,在這種情況下系統每隔nIDEvent毫秒會向hWnd窗口投遞WM_TIMER消息。唯一需要注意的是:

  1.自2000起,uElapse範圍是USER_TIMER_MINIMUM到USER_TIMER_MAXIMUM。超出得話,uElapse設置爲1。

  2.WM_TIMER消息其實是在DispatchMessage函數中直接調用hWnd的窗口過程,並且優先級很低,只有在消息隊列中沒有其它消息的情況下,DispatchMessage纔會考慮WM_TIMER。

  3.使用相同的nIDEvent可以重置這個Timer,並且KillTimer(hWnd,nIDEvent)來銷燬這個Timer。

  我們再來考慮hWnd爲NULL的情況:

  1.首先,最重要的是KillTimer時,傳入的Timer Id必須是SetTimer的返回值,而不是調用SetTimer時傳入的nIDEvent參數。

  2.調用SetTimer時,如果nIDEvent爲0或者是其它沒有被使用的Timer Id,則SetTimer會返回一個新的Timer Id。否則,就是重新設置這個Timer。

  3.如果有lpTimerFunc的話,則lpTimerFunc的參數nIDEvent是SetTimer返回的值,而不是你調用SetTimer時傳入的值。

  最後看一下lpTimerFunc不爲NULL的情況:lpTimerFunc會在DispatchMessage函數中被直接調用,而不會去調用hWnd的窗口過程(也就是說收不到這個消息),無論hWnd是不是NULL。(這裏,msdn中貌似有點問題,SetTimer的Remark部分說lpTimerFunc會在默認窗口中被調用,而WM_TIMER中說lpTimerFunc在DispatchMessage中被調用)

  應用

  使用lpTimerFunc可以做一個延時的操作,或者把某些操作推遲到下一個消息循環,而不需要爲窗口定義一個新的Timer Id。

  例如,我很喜歡這樣寫:

  struct _DATA

  {

  //....

  };

  void CALLBACK TimerProc(HWND hwnd,

  UINT uMsg,

  UINT_PTR idEvent,

  DWORD dwTime)

  {

  _DATA * data = (_DATA*)idEvent;

  KillTimer(hwnd,idEvent);

  //do something

  free(data);

  }

  _DATA * data = (_DATA*)malloc(sizeof(_DATA));

  SetTimer(AfxGetMainWindow()->m_hWnd,(UINT_PTR)data,10,&TimerProc);

  首先,使用了TimerProc,不會使窗口收到WM_TIMER消息,那樣可以使用idEvent來傳遞自定義數據而不會和窗口自己使用的Timer id衝突。

  其次,第一個參數hWnd不能爲NULL,否則TimerProc的idEvent參數就不是你傳入的自定義數據了。

  最後,msdn說SetTimer不能跨線程使用,所以最好不要用這樣的方法在向ui線程來插入代碼,還是老老實實的發消息吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章