千家信息网

如何使用Qt实现线程与定时器

发表于:2025-01-23 作者:千家信息网编辑
千家信息网最后更新 2025年01月23日,这篇文章主要介绍如何使用Qt实现线程与定时器,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、定时器QTimer类The QTimer class provides repet
千家信息网最后更新 2025年01月23日如何使用Qt实现线程与定时器

这篇文章主要介绍如何使用Qt实现线程与定时器,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

一、定时器QTimer类

The QTimer class provides repetitive and single-shot timers.

The QTimer class provides a high-level programming interface for timers. To use it, create a QTimer, connect its timeout() signal to the appropriate slots, and call start(). From then on, it will emit the timeout() signal at constant intervals.

上面这段话摘自Qt助手文档,我们使用QTimer类定义一个定时器,它可以不停重复,也可以只进行一次便停止。

使用起来也很简单:

QTimer *timer = new QTimer(this);connect(timer, SIGNAL(timeout()), this, SLOT(update()));timer->start(1000);

创建一个QTimer对象,将信号timeout()与相应的槽函数相连,然后调用start()函数。接下来,每隔一段时间,定时器便会发出一次timeout()信号。

更多用法这里就不讲了,您可以自行参考官方文档。比如如何停止、如何令定时器只运行一次等。

二、在多线程中使用QTimer

1.错误用法

您可能会这么做:

子类化QThread,在线程类中定义一个定时器,然后在run()方法中调用定时器的start()方法。

TestThread::TestThread(QObject *parent)    : QThread(parent){    m_pTimer = new QTimer(this);    connect(m_pTimer, &QTimer::timeout, this, &TestThread::timeoutSlot);} void TestThread::run(){    m_pTimer->start(1000);} void TestThread::timeoutSlot(){    qDebug() << QString::fromLocal8Bit("当前线程id:") << QThread::currentThread();}

接下来在主线程中创建该线程对象,并调用它的start()方法:

m_pThread = new TestThread(this);m_pThread->start();

看似十分自然,没有什么不妥,然而,编译器将通知下面的错误信息:

QObject::startTimer: Timers cannot be started from another thread

——定时器不能被其它线程start。

我们来分析一下:

刚开始只有主线程一个,TestThread的实例是在主线程中创建的,定时器在TestThread的构造函数中,所以也是在主线程中创建的。

当调用TestThread的start()方法时,这时有两个线程。定时器的start()方法是在另一个线程中,也就是TestThread中调用的。

创建和调用并不是在同一线程中,所以出现了错误。

具体的原理可参考官方文档——点我

每个QObject实例都有一个叫做"线程关系"(thread affinity)的属性,或者说,它处于某个线程中。

默认情况下,QObject处于创建它的线程中。

当QObject接收队列信号(queued signal)或者传来的事件(posted event),槽函数或事件处理器将在对象所处的线程中执行。

根据以上的原理,Qt使用计时器的线程关系(thread affinity)来决定由哪个线程发出timeout()信号。正因如此,你必须在它所处的线程中start或stop该定时器,在其它线程中启动定时器是不可能的。

2.正确用法一

在TestThread线程启动后创建定时器。

void TestThread::run(){    m_pTimer = new QTimer();    m_pTimer->setInterval(1000);    connect(m_pTimer, &QTimer::timeout, this, &TestThread::timeoutSlot);    m_pTimer->start();    this->exec();}

有些地方需要注意:

1.不能像下面这样给定时器指定父对象

m_pTimer = new QTimer(this);

否则会出现以下警告:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is TestThread(0x709d88), parent's thread is QThread(0x6e8be8), current thread is TestThread(0x709d88) 

因为TestThread对象是在主线程中创建的,它的QObject子对象也必须在主线程中创建。所以不能指定父对象为TestThread。

2.必须要加上事件循环exec()

否则线程会立即结束,并发出finished()信号。

另外还有一点需要注意,与start一样,定时器的stop也必须在TestThread线程中,否则会出错。

void TestThread::timeoutSlot(){    m_pTimer->stop();    qDebug() << QString::fromLocal8Bit("当前线程id:") << QThread::currentThread();}

上面的代码将出现以下错误:

QObject::killTimer: Timers cannot be stopped from another thread

综上,子类化线程类的方法可行,但是不太好。

3.正确用法二

无需子类化线程类,通过信号启动定时器。

TestClass::TestClass(QWidget *parent)    : QWidget(parent){    m_pThread = new QThread(this);    m_pTimer = new QTimer();    m_pTimer->moveToThread(m_pThread);    m_pTimer->setInterval(1000);    connect(m_pThread, SIGNAL(started()), m_pTimer, SLOT(start()));    connect(m_pTimer, &QTimer::timeout, this, &ThreadTest::timeOutSlot, Qt::DirectConnection);}

通过moveToThread()方法改变定时器所处的线程,不要给定时器设置父类,否则该函数将不会生效。

在信号槽连接时,我们增加了一个参数——连接类型,先看看该参数可以有哪些值:

  • Qt::AutoConnection:默认值。如果接收者处于发出信号的线程中,则使用Qt::DirectConnection,否则使用Qt::QueuedConnection,连接类型由发出的信号决定。

  • Qt::DirectConnection:信号发出后立即调用槽函数,槽函数在发出信号的线程中执行。

  • Qt::QueuedConnection:当控制权返还给接收者信号的事件循环中时,开始调用槽函数。槽函数在接收者的线程中执行。

回到我们的例子,首先将定时器所处的线程改为新建的线程,然后连接信号槽,槽函数在定时器所处的线程中执行。

以上是"如何使用Qt实现线程与定时器"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!

线程 定时器 信号 函数 对象 方法 是在 中创 事件 错误 子类 接收者 文档 参考 接下来 内容 原理 参数 官方 实例 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 重庆星月网络技术有限公司 石家庄互联网科技公司 创造与魔法刚开服务器什么样子 雕刻机编程用什么软件开发 网络安全法不同意见 合肥龙芯服务器报价 文广局网络安全风险评估总结 图书馆 大型 数据库设计 游客服务器英文 联想服务器硬盘检测不到 京东云服务器配置管理ip 我的世界被炸的服务器有什么 如何读取数据库文件 正在发布的数据库怎么分离 关于疫情的网络安全班会 重庆新一代软件开发品质保障 什么叫企业软件开发业务需求 openpyxl 数据库 山东特亿宝互联网科技工作 计算机网络技术职业素养目标 网络安全法人力资源行业解读 软件开发过程中存在问题 江阴互联网智能科技产品进口 小白数据库2020续航 服务器权限管理管理软件 服务器5w 数据库的R功能 raid5重建服务器关机 湖州java软件开发自学步骤 学生会网络技术部是干什么的
0