在最近的項目開發中,我發現有的人喜歡用QThread來實現需要循環執行的工作流,而有的人又喜歡用QTimer來實現。
在表面上,兩種實現方式似乎都可以,但我覺得QTimer的精度可能會有問題,首先看一下別的coder關於這個問題的探索。
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毫秒
