首页 > 其他分享 >Qt 多线程中使用QTimer和信号、槽 QObject::startTimer: Timers cannot be started from another thread

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

时间:2024-02-29 18:57:04浏览次数:24  
标签:Qt thread timer t1 线程 多线程 MainWindow QTimer

多线程中使用QTimer

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

Cannot create children for a parent that is in a different thread.
或者
QObject::startTimer: Timers cannot be started from 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 {
 8     Q_OBJECT
 9 public:
10     MyThread();
11     virtual void run()override;
12     QTimer* timer;
13 
14 signals:
15     void TestThread_Signal();   //自定义的信号
16 public slots:
17     void TestThread_Slot();
18     void wode();
19 };
20 
21 #endif // MYTHREAD_H

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

 1 MainWindow::MainWindow(QWidget *parent) :
 2     QMainWindow(parent),
 3     ui(new Ui::MainWindow)
 4 {
 5     ui->setupUi(this);
 6     qDebug()<<"Main ThreadID"<< this->thread()->currentThreadId();
 7 //    t1.moveToThread(&t1);
 8     t1.timer = new QTimer();
 9     t1.timer->setInterval(90);
10     t1.start();
11 }
12 void MyThread::run()
13 {
14     connect(timer, &QTimer::timeout, this, &MyThread::wode);
15     timer->start();
16     this->exec();//这个是Qt的消息循环,只有加这个才可以监听信号
17 }

更改代码1:

将定时器的在堆中的函数

 1 MainWindow::MainWindow(QWidget *parent) :
 2     QMainWindow(parent),
 3     ui(new Ui::MainWindow)
 4 {
 5     ui->setupUi(this);
 6     qDebug()<<"Main ThreadID"<< this->thread()->currentThreadId();
 7 //    t1.moveToThread(&t1);
 8     t1.start();
 9 }
10 void MyThread::run()
11 {
12 //    connect(&timer,&QTimer::timeout,this,[](){qDebug()<<"Timer goes";});
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     {
3         qDebug()<<"same";
4     };
 1 MainWindow::MainWindow(QWidget *parent) :
 2     QMainWindow(parent),
 3     ui(new Ui::MainWindow)
 4 {
 5     ui->setupUi(this);
 6     qDebug()<<"Main ThreadID"<< this->thread()->currentThreadId();
 7 //    t1.moveToThread(&t1);
 8     t1.start();
 9 }
10 void MyThread::run()
11 {
12 //    connect(&timer,&QTimer::timeout,this,[](){qDebug()<<"Timer goes";});
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 {
 5     ui->setupUi(this);
 6     qDebug()<<"Main ThreadID"<< this->thread()->currentThreadId();
 7     t1.moveToThread(&t1);
 8     t1.start();
 9 }
10 void MyThread::run()
11 {
12     timer = new QTimer(this);
13     if(this->thread() == timer->thread())
14     {
15         qDebug()<<"same";
16     };
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()来监听信号

标签:Qt,thread,timer,t1,线程,多线程,MainWindow,QTimer
From: https://www.cnblogs.com/ybqjymy/p/18045131

相关文章

  • Qt Cannot open include file: 'QtConcurrent': No such file or directory
    假期手痒用Qt写了个便笺程序,其中文件操作用到了QtConcurrent模块。噼里啪啦,一通猛如虎的操作下来,代码写完了,愉快地build+run一套,结果报错了:(Cannotopenincludefile:'QtConcurrent':Nosuchfileordirectory编译不过一声吼,操起鼠标查google。官方文档就是这么写的看......
  • Qt 多线程中使用信号槽的示例
    之前对线程理解得不深入,所以对Qt的线程机制没有搞清楚,今天写一篇文章总结一下,如有错误,欢迎指出。    首先需要理解线程是什么,线程在代码中的表现其实就是一个函数,只不过这个函数和主线程的函数同时运行,写C语言的都知道,一般代码是从main()函数开始运行的,每个线程都有一......
  • Cause: java.sql.SQLException: Thread stack overrun: 266768 bytes used of a 2867
    ###Cause:java.sql.SQLException:Threadstackoverrun:266768bytesusedofa286720bytestack,and20000bytesneeded.Use'mysqld--thread_stack=#'tospecifyabiggerstack.;uncategorizedSQLException;SQLstate[HY000];errorcode[143......
  • 代替Thread.sleep的平替方法
    packagecool.islj.thread;importjava.time.Duration;importjava.util.function.BooleanSupplier;publicclassThreadUtils{/***等待(supplier一开始为true则不等待)*@paramperiod检查周期,supplier一开始为false时的最低等待时间*@paramtim......
  • C++ 多线程笔记1 线程的创建
    C++多线程笔记1线程的创建里面代码会用到的头文件#include<iostream>#include<string>#include<memory>#include<thread>#include<vector>#include<stdlib.h>#include<cmath>#include<chrono>#include<ctime>入门例子vo......
  • c++ queue在多线程中的使用
    queue队列,先进先出。多线程的一种使用案例:生产者每3spush一个元素消费者每5s才能pop一个元素(队首)那么,2个消费者就可以及时地消耗掉push的元素。#include<iostream>#include<thread>#include<mutex>#include<queue>std::queue<int>m_queue;std::mutexm_mutex;std:......
  • VS Qt - cmake项目中添加运行时命令行参数
    1、VS在项目目录中找到.vs目录--->launch.vs.json{"version":"0.2.1","defaults":{},"configurations":[{"type":"default","project":"CMakeLists.txt",......
  • OpenCV计数应用 c++(QT)
    一、前言为了挑战一下OpenCV的学习成果,最经一直在找各类项目进行实践。机缘巧合之下,得到了以下的需求:要求从以下图片中找出所有的近似矩形的点并计数,重叠点需要拆分单独计数。二、解题思路1.图片作二值化处理autoimage=cv::imread("points.jpg");cv::Matborder;//为......
  • c# winform 多线程
    ​  privateTaskSchedulermpr_ts_UIContext;    privatevoidbutton1_Click(objectsender,EventArgse)    {      progressBar1.Visible=true;      progressBar1.Value=0; //清空进度条      progress......
  • Qt 随机数生成器:QRandomGenerator
    一、描述QRandomGenerator可用于从高质量随机数生成器生成随机值。与C++随机引擎一样,QRandomGenerator可以通过构造函数使用用户提供的值作为种子。播种时,此类生成的数字序列是确定性的。也就是说,给定相同的种子数据,QRandomGenerator会生成相同的数字序列。给定不同的种......