Qt 异步实现事件的定时执行 - QTimer和QThread的联合使用

异步实现事件的定时执行 - QTimer和QThread的联合使用

引言

在 Qt 中,如果想要定时执行某些事件或函数,通常会使用 QTimer 类。QTimer 允许设置一个时间间隔,当这个时间间隔过去后,它会发出一个信号。可以将这个信号连接到一个槽函数,从而在该时间间隔到达时执行特定的操作。如果想要实现定时的操作是异步执行 (不阻塞主线程),可通过moveToThread将定时器移动到一个线程中,信号和槽的连接类型使用Qt::DirectConnection,保证槽函数执行是在定时器的线程中。效果如下图所示 (一秒执行一次):

在这里插入图片描述

一、核心源码

    1. 创建定时器以及线程,设定执行事件
    this->m_timer = new QTimer(nullptr);
    this->m_thread = new QThread(this);

    m_timer->setInterval(1000);
    m_timer->moveToThread(m_thread);
    connect(m_timer, &QTimer::timeout, this, [&](){
        QString time = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
        qDebug()<< time << " timer Thread ID:" << QThread::currentThreadId();
    }, Qt::DirectConnection);
    connect(m_thread, &QThread::started, m_timer, QOverload<>::of(&QTimer::start));
    connect(m_thread, &QThread::finished, m_timer, &QTimer::stop);
    m_thread->start();
    qDebug() << "Main Thread ID:" << QThread::currentThreadId();

首先创建定时器和线程,设定定时器间隔时间为1秒,并将定时器移动到线程中。方便起见直接使用兰姆达表达式设定定时器的定时槽函数. 使用信号和槽的形式调用定时器相关函数 (开始和停止)。最后启动线程即可.

    1. 内存释放
    m_thread->quit();
    m_thread->wait();
    m_thread->deleteLater();
    m_timer->deleteLater();

一般在父类或者父窗体的析构函数中执行,停止执行,释放内存。

二、其信号和槽函数简述

信号与槽相关知识可参考:
Qt 信号与槽的使用详解 - 多种绑定形式、同步异步、Lambda表达式等:https://blog.csdn.net/qq_38204686/article/details/139702275

    1. 使用信号和槽的形式调用定时器相关函数
      由于定时器已经被移动到线程中,所以不能直接在主线程中调用定时器相关函数。比如执行定时器停止m_timer->stop();会显示QObject::killTimer: Timers cannot be stopped from another thread

可参考
Qt: QTimer和QThread:https://www.cnblogs.com/lingdhox/p/4218051.html
https://stackoverflow.com/questions/53200294/qthread-with-qtimer-connection-issues

    1. 定时器开始槽函数需使用QOverload<>::of重载
      &QTimer::start有多个重载函数,比如void QTimer::start(int msec)void QTimer::start(),需使用QOverload<>::of指定调用哪一个重载函数 - (在<>中指明参数,比如<int>)。
      如果只这样写connect(m_thread, &QThread::started, m_timer, &QTimer::start);会报错,
      这样connect(m_thread, SIGNAL(started()), m_timer, SLOT(start()));是可行的,但不建议。

可参考
QThread with QTimer connection issues:https://stackoverflow.com/questions/53200294/qthread-with-qtimer-connection-issues
QT-信号槽有多个重载版本{ QOverload<_>::of(&::) }:https://blog.csdn.net/ugetoneshot/article/details/139169027

三、定时器及其moveToThread简述

    1. 创建定时器new QTimer(nullptr) 参数parent为空而不是this
      后续需要将定时器移动到另一线程,所以其父对象需为空

void QObject::moveToThread(QThread *targetThread)的官方解释:
更改此对象及其子对象的线程相关性。如果对象有父对象,则无法移动该对象,事件处理将在targetThread中继续。使用时需注意:此函数只能将对象从当前线程“推”到另一个线程,而不能将对象从任意线程“拉”到当前线程。

    1. 关于定时器的精度问题.
      如下方左图所示,近似每秒一触发,但是误差在2-3毫秒,设置setTimerType(Qt::PreciseTimer);之后误差只有1毫秒。

在这里插入图片描述 在这里插入图片描述

可参考
QT使用高精度定时器:https://blog.csdn.net/ljjjjjjjjjjj/article/details/130189550

相关推荐

  1. Qt定时器QTimer

    2024-07-10 09:34:02       25 阅读
  2. C++| QT定时器QTimer

    2024-07-10 09:34:02       19 阅读
  3. QTimer 指针类型引用类型使用区别

    2024-07-10 09:34:02       43 阅读
  4. 在 Linux 使用 cron 定时执行任务注意事项

    2024-07-10 09:34:02       15 阅读
  5. Qt : 实现串口同步异步读写消息

    2024-07-10 09:34:02       25 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 09:34:02       4 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 09:34:02       5 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 09:34:02       4 阅读
  4. Python语言-面向对象

    2024-07-10 09:34:02       4 阅读

热门阅读

  1. springBoot整合mongodb

    2024-07-10 09:34:02       6 阅读
  2. STM32 系统时钟初始化函数和延时函数

    2024-07-10 09:34:02       8 阅读
  3. Oracle数据库服务器CPU占用率巨高的问题排查思路

    2024-07-10 09:34:02       10 阅读
  4. WebKit简介及工作流程

    2024-07-10 09:34:02       9 阅读
  5. nlp中tokenizer用法

    2024-07-10 09:34:02       10 阅读
  6. 2.Date类型的请求参数

    2024-07-10 09:34:02       10 阅读
  7. 基于antdesign封装一个react的上传组件

    2024-07-10 09:34:02       12 阅读
  8. Leetcode100.判断两颗二叉树是否相同

    2024-07-10 09:34:02       9 阅读
  9. 防止应用调试分析IP被扫描加固实战教程

    2024-07-10 09:34:02       9 阅读