【2017-01-08】QTimer與QThread的調度時間精度


在最近的項目開發中,我發現有的人喜歡用QThread來實現需要循環執行的工作流,而有的人又喜歡用QTimer來實現。

在表面上,兩種實現方式似乎都可以,但我覺得QTimer的精度可能會有問題,首先看一下別的coder關於這個問題的探索。

QTimer和Qthread的調度時間精度

http://blog.csdn.net/dijunfeng/article/details/7272475

作者:dijunfeng

最近做的一個模擬嵌入式設備的項目中,要求事件的響應精度在1毫秒左右,特地編寫代碼測試了一下QTimer的定時精度和QThread中的msleep()的時間精度。

QT的幫助中對於QTimer的時間精度問題是這么寫的:

Timers will never time out earlier than the specified timeout value and they are not guaranteed to time out at the exact value specified.

In many situations, they may time out late by a period of time that depends on the accuracy of the system timers.

The accuracy of timers depends on the underlying operating system and hardware.

Most platforms support a resolution of 1 millisecond, though the accuracy of the timer will not equal this resolution in many real-world situations.

If Qt is unable to deliver the requested number of timer clicks, it will silently discard some.

我們的測試函數用到了windows的高精度時間讀取函數,如下所示

 #include <Windows.h>

#include <math.h>

#define TIMER_INTVL 1000 //毫秒

#define ARRAY_LEN 1 //數組長度

//傳入調用時間間隔,打印出最大和平均時間誤差

void testTimer(int intvl_us)

{

  static bool inited = false;

  static LARGE_INTEGER lastT;

  static LARGE_INTEGER freq;

  LARGE_INTEGER now;

  static int usarray[ARRAY_LEN];

  static int index = 0;

  static int maxus = 0, averus = 0, difus;//時間差

  QString info("最大時間差:");

  if(!inited)

  {

    memset(usarray, 0, sizeof(int)*ARRAY_LEN);

    QueryPerformanceCounter(&lastT);//獲取第一次進入時的時間

    QueryPerformanceFrequency(&freq);//獲取時鍾頻率

    inited = true;

    return;

  }

  QueryPerformanceCounter(&now);

  difus = ((now.QuadPart-lastT.QuadPart)*1000000)/freq.QuadPart;

  difus = abs(difus-intvl_us);

  usarray[index++] = difus;

  maxus = maxus>difus?maxus:difus;

  if(index == ARRAY_LEN)

  {

    index = 0;

    for(int i=0; i<ARRAY_LEN; i++)

      averus += usarray[i];

    averus /= ARRAY_LEN;

    info = info + QString::number(maxus) + " 平均誤差 " + QString::number(averus);

    gSimDrvDlg->putInfo(info);

    maxus = 0;

    averus = 0;

  }

  lastT = now;

}

 

把此函數設為QTimer的超時響應函數,在32位windows7下測試QTimer的不同定時周期的調度誤差如下:

1ms周期:

  最大:30、40毫秒

  平均誤差:100微秒左右
 
10ms周期:
  最大:2、3毫秒,跳動比較大,也有20毫秒多過
  平均誤差:200多微秒
 
100ms周期:
  最大:20多毫秒
  平均誤差:10毫秒左右
 
1秒即1000ms周期
  平均誤差十幾毫秒
 
把此函數稍加改動,也可以放到QThread的run()函數中測試一下QThread::msleep的時間精度。
在windows下,由於操作系統的本身設計理念問題,定時器的調度誤差是比較大的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM