zoukankan      html  css  js  c++  java
  • 【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下,由于操作系统的本身设计理念问题,定时器的调度误差是比较大的。
  • 相关阅读:
    NPOIHelper
    NPOI.dll 用法:单元格、样式、字体、颜色、行高、宽度 读写excel
    SQL中的循环、for循环、游标
    .net mvc datatables中orderby动态排序
    MVC中给TextBoxFor设置默认值和属性
    定义实体系列-@JsonIgnoreProperties注解
    微信公众号登录与微信开放平台登录区别
    http-Post请求,Post Body中的数据量过大时出现的问题
    .net core Linux 安装部署
    二、微信公众号开发-获取微信用户信息(.net版)
  • 原文地址:https://www.cnblogs.com/dengwenwu/p/6261385.html
Copyright © 2011-2022 走看看