当前位置: 首页 > 网络知识

Qt 多线程中使用QTimer和信号、槽 QObject::startTimer: Timers cannot be started from another thread

时间:2026-01-29 09:26:45

多线程中使用QTimer

我们可能在Qt的多线程中使用QTimer中都会遇到一个错误:

Cannot create children for a parent that is in a different thread.
或者
QObject::startTimer: Timers cannot be started fr another thread

QTimer定时器不能在不同的线程中启动。
出现这个主要原因是没有很好的将主线程和子线程进行区分。
我们看以下的多线程代码:(在Qt中的多线程)
这个是定义一个类继承自QThread,并且重写其中的虚函数run。之后,启动线程run函数就在子线程中运行了。

1 #ifndef MYTHREAD_H 2 #define MYTHREAD_H 3 #include <QThread> 4 #include <QTimer> 5 6 class MyThread : public QThread 7 ; 20 21 #endif // MYTHREAD_H

错误代码1:
QObject::startTimer: Timers cannot be started fr another thread
出现这个原因:主要是在主线程中进行Qtimer在堆中的内存分配,因此,该定时器属于同一个线程,如果在子线程中进行start,那么就会在别的线程中开启主线程中的定时器。Qt不允许这样操作。

1 MainWindow::MainWindow(QWidget *parent) : 2 QMainWindow(parent), 3 ui(new Ui::MainWindow) 4 12 void MyThread::run() 13

更改代码1:

将定时器的在堆中的函数

1 MainWindow::MainWindow(QWidget *parent) : 2 QMainWindow(parent), 3 ui(new Ui::MainWindow) 4 10 void MyThread::run() 11 ); 13 //不能加this 14 timer = new QTimer(); 15 timer>setInterval(90); 16 connect(timer, &QTimer::timeout, this, &MyThread::wode); 17 timer>start(); 18 //一定要有exec() 19 this>exec(); 20 }

运行结果:
可以看出槽函数在主线程中运行,这也就说明了t1对象属于主线程。

错误代码2:
经历了上面的那个例子,我们可以看出主线程和子线程的区别之处。那么,我们根据下面这个例子再forward。。。
啊哦~~~报警告了。

Cannot create children for a parent that is in a different thread.
这是为什么呢?
经过我们之前的分析,t1也即是那个线程类对象在主线程中,只有run函数体的部分属于子线程,那么,QTimer现在在子线程new对象,QTimer指向的内存即是子线程中,
(注意:timer是在主线程中,因为它是栈区的。)
你却将this(t1)传为它的父对象,怎么可能不报错呢???
因此,这既是有的博客说的千万不要加this的用意之处。我们可以通过以下代码进行测试:

1 if(this>thread() == timer>thread()) 2 ;
1 MainWindow::MainWindow(QWidget *parent) : 2 QMainWindow(parent), 3 ui(new Ui::MainWindow) 4 10 void MyThread::run() 11 ); 13 //不能加this 14 timer = new QTimer(this); 15 timer>setInterval(90); 16 connect(timer, &QTimer::timeout, this, &MyThread::wode); 17 timer>start(); 18 //一定要有exec() 19 this>exec(); 20 }

更改代码2:

用到了movetoThread函数进行。

1 MainWindow::MainWindow(QWidget *parent) : 2 QMainWindow(parent), 3 ui(new Ui::MainWindow) 4 10 void MyThread::run() 11 ; 17 timer>setInterval(90); 18 connect(timer, &QTimer::timeout, this, &MyThread::wode); 19 timer>start(); 20 //一定要有exec() 21 this>exec(); 22 }

运行结果:我们可以看出当通过moveToThread函数之后,我们就可以进行。
注意:从测试案例中我们可以看出。槽函数也是打印的子线程的线程号,因此,moveToThread函数会将t1移动到子线程中,new定时器的适合加this也问题不大了。因为,父子对象处于一个线程了。

经过上面的分析,我们对子线程和主线程的区分已经了解了。因此,在多线程中使用信号和槽就很容易了。

两点需要注意:
1、需要添加Q_OBJECT宏
2、需要exec()来监听信号



上一篇:Visual Studio 性能探查器排查内存泄漏
下一篇:Visual Leak Detector 简介
Qt
  • 英特尔与 Vertiv 合作开发液冷 AI 处理器
  • 英特尔第五代 Xeon CPU 来了:详细信息和行业反应
  • 由于云计算放缓引发扩张担忧,甲骨文股价暴跌
  • Web开发状况报告详细介绍可组合架构的优点
  • 如何使用 PowerShell 的 Get-Date Cmdlet 创建时间戳
  • 美光在数据中心需求增长后给出了强有力的预测
  • 2027服务器市场价值将接近1960亿美元
  • 生成式人工智能的下一步是什么?
  • 分享在外部存储上安装Ubuntu的5种方法技巧
  • 全球数据中心发展的关键考虑因素
  • 英特尔与 Vertiv 合作开发液冷 AI 处理器

    英特尔第五代 Xeon CPU 来了:详细信息和行业反应

    由于云计算放缓引发扩张担忧,甲骨文股价暴跌

    Web开发状况报告详细介绍可组合架构的优点

    如何使用 PowerShell 的 Get-Date Cmdlet 创建时间戳

    美光在数据中心需求增长后给出了强有力的预测

    2027服务器市场价值将接近1960亿美元

    生成式人工智能的下一步是什么?

    分享在外部存储上安装Ubuntu的5种方法技巧

    全球数据中心发展的关键考虑因素