QObject::killTimer: timers cannot be stopped from another thread
原因:出现这个错误的原因在于在次线程中执行主线程对象的一些操作引起的
使用定时器的注意事项
- 不能跨线程启动定时器和停止定时器。
- 不能跨线程启动一个定时器关联的对象,但在另一个线程释放此定时器关联的对象,即定时器相关的逻辑和对象只能用在一个线程中。
例子分析:
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
#include "autosampleservice.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void Init();
private slots:
void on_btnStop_clicked();
signals:
void sigStop();
void sigInit();
private:
Ui::MainWindow *ui;
AutoSampleService *pAutoSampleService=nullptr;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QThread>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug()<<"MainWindow----current thread id:"<<QThread::currentThreadId()<<endl;
pAutoSampleService=new AutoSampleService();
connect(this,SIGNAL(sigInit()),pAutoSampleService,SLOT(SlotInit()),Qt::QueuedConnection);
connect(this,SIGNAL(sigStop()),pAutoSampleService,SLOT(Stop()),Qt::QueuedConnection);
Init();
}
void MainWindow::Init()
{
QThread *t=new QThread();
pAutoSampleService->moveToThread(t);
t->start();
//emit sigInit();
pAutoSampleService->SlotInit();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btnStop_clicked()
{
emit sigStop();
}
//autosampleservice.h
#ifndef AUTOSAMPLESERVICE_H
#define AUTOSAMPLESERVICE_H
#include<QTimer>
#include<QObject>
class AutoSampleService:public QObject
{
Q_OBJECT
public:
AutoSampleService();
public slots:
void SlotInit();
void RecvTimeOut();
void Stop();
private:
QTimer* RecvTimer=nullptr;
};
#endif // AUTOSAMPLESERVICE_H
#include "autosampleservice.h"
#include<QThread>
#include<QDebug>
AutoSampleService::AutoSampleService()
{
}
void AutoSampleService::SlotInit()
{
qDebug()<< "AutoSampleService Init----current thread id:"<<QThread::currentThreadId()<<endl;
RecvTimer=new QTimer();
RecvTimer->start(5000);
connect(RecvTimer,SIGNAL(timeout()),this,SLOT(RecvTimeOut()));
}
void AutoSampleService::RecvTimeOut()
{
qDebug()<< "RecvTimeOut----current thread id:"<<QThread::currentThreadId()<<endl;
}
void AutoSampleService::Stop()
{
qDebug()<< "AutoSampleService Stop----current thread id:"<<QThread::currentThreadId()<<endl;
RecvTimer->stop();
}
点击停止按钮后,运行结果如下:
原因分析
因pAutoSampleService->SlotInit() 主线程中直接调用SlotInit函数创建RecvTimer定时器,即RecvTimer定时器启动在主线程;当点击停止按钮后,在子线程进行RecvTimer定时器停止操作
解决方法:
调整上述代码
void MainWindow::Init()
{
QThread *t=new QThread();
pAutoSampleService->moveToThread(t);
t->start();
emit sigInit();
}