在最近的项目开发中,我发现有的人喜欢用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下,由于操作系统的本身设计理念问题,定时器的调度误差是比较大的。

【2017-01-08】QTimer与QThread的调度时间精度的更多相关文章

  1. java编程如何实现2017-01-16 22:28:26.0这样的时间数据,转换成2017:01:16:22:28:26这样的时间数据

    不多说,直接上干货! timereplace.java package zhouls.bigdata.DataFeatureSelection.util; /* * 这个程序,是用来做补充的 */ p ...

  2. 【web开发 | 移动APP开发】 Web 移动开发指南(2017.01.05更新)

    版本记录 - 版本1.0 创建文章(2016.12.30) - 版本1.1 更正了hybird相关知识:增加了参考文章(2017.01.05): + Web APP更正为响应式移动站点与页面,简称响应 ...

  3. Mysql Innodb 性能参数设置 https://www.rathishkumar.in/2017/01/how-to-allocate-innodb-buffer-pool-size-in-mysql.html

    参考原文: https://www.rathishkumar.in/2017/01/how-to-allocate-innodb-buffer-pool-size-in-mysql.html 查看系统 ...

  4. 在不开启事件循环的线程中使用QTimer(QThread::run函数自带事件循环,在构造函数里创建线程,是一种很有意思的线程用法) good

    引入 QTimer是Qt自带的定时器类,QTimer运行时是依赖于事件循环的,简单来说,在一个不开启事件循环(未调用exec() )的线程中,QTimer是无法使用的.通过分析Qt源码可发现,调用QT ...

  5. 第08讲:Flink 窗口、时间和水印

    Flink系列文章 第01讲:Flink 的应用场景和架构模型 第02讲:Flink 入门程序 WordCount 和 SQL 实现 第03讲:Flink 的编程模型与其他框架比较 第04讲:Flin ...

  6. QTimer在QThread环境中失效的问题

    QTimer在非QThread的环境下能正常工作.但在QThread环境下,需要做一些改动才能正常工作. 创建Qt的线程有两种方式: 1. 子例化QThread 可以在虚函数run中启动定时器,大致的 ...

  7. Qt: QTimer和QThread

    让QTimer 跑在其他线程. 一般写法如下. 1. 在main thread中为worker thread指定定时器. QThread* thread = new QThread(this); th ...

  8. TIOBE.2017.01最新编程语言排行榜

    Jan 2017     Jan 2016     Change     Programming Language     Ratings     Change1    1        Java   ...

  9. pyqt QTimer,QThread例子学习

    # -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' from PyQt4.QtGui import * from PyQ ...

随机推荐

  1. ruby执行周期性任务

    1.前言      无论是用ruby做系统管理,还是用rails做web开发,都可能遇到周期性任务,它们按照一定时间周期(1小时,2天......)持续地触发.在ruby中,我认为一次性任务使用sid ...

  2. windows server服务器上部署java+tomcat网站域名配置

    如果只是部署java项目的话,可以把IIS删除,然后在服务器上安装jdk tomcat 配置好环境变量,就和你在自己计算机上开发一样,把你的项目war包拷到tomcat下的webapps里(任意目录都 ...

  3. i.mx6 Android5.1.1 build解析

    参考资料:理解 Android Build 系统 把总结放前面: 1. 常用编译命令 make clean 执行清理,等同于:rm -rf out/. make sdk 编译出 Android 的 S ...

  4. 16.Generator 函数的异步应用

    Generator 函数的异步应用 Generator 函数的异步应用 异步编程对 JavaScript 语言太重要.Javascript 语言的执行环境是"单线程"的,如果没有异 ...

  5. Microsoft.AspNet.Identity 的简单使用

    要完成一个简单的注册,登陆,至少需要实现Identity中的3个接口 IUser IUserStore<TUser> : IDisposable where TUser : IUser I ...

  6. C# BBcode 转 Markdown

    本文告诉大家一个简单的方法从 BBcode 转为 Markdown 本文的方法都是使用正则转换,现在支持的代码只有很少的常用标签,如果大家发现有转换失败的,请帮我修改代码,估计代码我不会进行修改. 最 ...

  7. [android] 手机卫士黑名单功能(ListView优化)

    上一篇记录了使用ListView展示出来了100条数据,当慢慢拖动的时候,不会有问题,但是当拖动很快的时候,应用会报anr错误 查看错误日志,看到报OutOfMemoryError,内存不足 List ...

  8. 您可能不知道的CSS元素隐藏“失效”以其妙用——张鑫旭

    一.CSS元素隐藏 在CSS中,让元素隐藏(指屏幕范围内肉眼不可见)的方法很多,有的占据空间,有的不占据空间:有的可以响应点击,有的不能响应点击.后宫选秀——一个一个看. { display: non ...

  9. PHP通用分页类page.php[仿google分页]

    <?php /** ** 通用php分页类.(仿Google样式) ** 只需提供记录总数与每页显示数两个参数.(已附详细使用说明..) ** 无需指定URL,链接由程序生成.方便用于检索结果分 ...

  10. python学习笔记之——python函数

    1.定义一个函数 你可以定义一个自己想要功能的函数,以下是简单的规则: 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号(). 任何传入参数和自变量必须放在圆括号中间.圆括号之间可以用于定 ...