无法从另一个线程Qt停止计时器



我正在开发Qt应用程序。在那里,我使用了两个线程,一个用于GUI,另一个用于处理。

我有工人班,有QTimer作为成员班。

.h文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
#include <QThread>
class Worker : public QObject
{
  Q_OBJECT
 public:
  Worker();
  QTimer t;
 public slots:
  void process();
  void startWorker();
};
namespace Ui {
 class MainWindow;
}
class MainWindow : public QMainWindow
{
  Q_OBJECT
  public:
   explicit MainWindow(QWidget *parent = nullptr);
   ~MainWindow();
 private:
   QThread workerThread;
   Worker wt;
 };
 #endif // MAINWINDOW_H

cpp文件

#include "mainwindow.h"
#include <QDebug>
#include <iostream>
Worker::Worker() : t(this)
{
 connect(&t, SIGNAL(timeout()), this, SLOT(process()));
}
void Worker::process()
{
  std::cout << "triggering timer" << std::endl;
}
void Worker::startWorker()
{
  t.start(1000);
}
MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent)
{
  wt.moveToThread(&workerThread);
  qDebug() << "worker thread " << wt.thread();
  qDebug() << "timer thread " << wt.t.thread();
  connect(&workerThread, SIGNAL(started()), &wt, SLOT(startWorker()));
  connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater);
  workerThread.start();
}
MainWindow::~MainWindow()
{
 workerThread.quit();
 workerThread.wait();
}

我可以毫无错误地启动线程。然而,当我关闭应用程序时,我会收到警告消息。

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

如果QTimer是worker类的子级,并且它已经被移动到线程,为什么Qt抱怨从不同的线程停止它?注意:我添加了日志来打印线程id,它在两种情况下都输出相同的值:

worker thread  QThread(0x72fdf0)
timer thread  QThread(0x72fdf0)

有人能解释一下吗?我不明白这里发生了什么

提前感谢

我终于能够通过以下方式修复错误:

  1. 将QTimer转换为指针
  2. 按照@Amfasis的建议添加插槽stopWorker
  3. 在该插槽中,不仅停止QTimer,而且删除它

感谢所有

您应该在QObject删除其自身之前停止计时器

在.h文件中,添加析构函数:

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker();
    ~Worker();
private:
    QTimer t;
public slots:
    void process();
    void startWorker();
    void stopWorker(); //this line was added
};

在.cpp文件中,添加:

Worker::stopWorker()
{
    t.stop();
}

和在构造函数中

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    ...
    connect(&workerThread, &QThread::finished, &wt, &Worker::stopWorker); //add this line!
    ...
}

您应该在任务对象槽中而不是在任务构造器中新建计时器。删除任务对象时停止计时器。

我的任务对象头:Worker.h

#pragma once
#include <QObject>
class QTimer;
class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);
    ~Worker();
public slots:
    void WorkerTaskStartSlot(void);
    void TaskFinished(void);
private slots:
    void TimerOutToDoSomethingSlot(void);
signals:
    void WorkertResultSig(void);
private:
    QTimer *m_pTimer = nullptr;
};

Worker.cpp:

#include "Worker.h"
#include <QDebug>
#include <QThread>
#include <QTimer>
Worker::Worker(QObject *parent) : QObject(parent)
{
    qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
Worker::~Worker()
{
    TaskFinished();
      qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}

void Worker::WorkerTaskStartSlot(void)
{
    qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
    emit WorkertResultSig();
    m_pTimer = new QTimer(this);
    connect(m_pTimer,&QTimer::timeout,this,&Worker::TimerOutToDoSomethingSlot);
    m_pTimer->start(1000);
}

void Worker::TaskFinished(void)
{
    qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
    if(m_pTimer)
    {
        if(m_pTimer->isActive())
        {
            m_pTimer->stop();
            qDebug()<<__FUNCTION__<<"stop timer"<< QThread::currentThreadId();
        }
        delete m_pTimer;
        m_pTimer = nullptr;
    }
}

void Worker::TimerOutToDoSomethingSlot(void)
{
    qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}

控制器标题:MainWindow.h

#pragma once
#include <QMainWindow>
class QPushButton;
class QWidget;
class Worker;
class QThread;
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
    void InitCtrl(void);
private slots:
    void StartTaskBtnSlot(const bool &checked);
    void WorkertResultSlot(void);
private:
    QPushButton *m_pStartTaskBtn = nullptr;
    QWidget *m_pCenterWidget = nullptr;
    Worker *m_pWorker = nullptr;
    QThread *m_pWorkerThread = nullptr;
};

主窗口.cpp

#include "MainWindow.h"
#include <QVBoxLayout>
#include <QPushButton>
#include <QWidget>
#include <QDebug>
#include <QThread>
#include "Worker.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    InitCtrl();
    qDebug()<<__FUNCTION__<<"mainwindow thread id"<< QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
}
void MainWindow::InitCtrl(void)
{
    m_pCenterWidget = new QWidget(this);
    m_pStartTaskBtn = new QPushButton(QStringLiteral("Start"),this);
    QVBoxLayout *pvertlayout = new QVBoxLayout();
    pvertlayout->addWidget(m_pStartTaskBtn);
    m_pCenterWidget->setLayout(pvertlayout);
    setCentralWidget(m_pCenterWidget);
    m_pStartTaskBtn->setCheckable(true);
    connect(m_pStartTaskBtn,&QPushButton::clicked,this,&MainWindow::StartTaskBtnSlot);
}
void MainWindow::StartTaskBtnSlot(const bool &checked)
{
    if(checked)
    {
        m_pStartTaskBtn->setText(QStringLiteral("Close"));
        m_pWorkerThread = new QThread();
        m_pWorker = new Worker();
        // move the task object to the thread BEFORE connecting any signal/slots
        m_pWorker->moveToThread(m_pWorkerThread);
        connect(m_pWorkerThread, SIGNAL(started()), m_pWorker, SLOT(WorkerTaskStartSlot()));
        connect(m_pWorker, SIGNAL(WorkertResultSig()), this, SLOT(WorkertResultSlot()));
        // automatically delete thread and task object when work is done:
        connect(m_pWorkerThread, SIGNAL(finished()), m_pWorker, SLOT(deleteLater()));
        connect(m_pWorkerThread, SIGNAL(finished()), m_pWorkerThread, SLOT(deleteLater()));

        m_pWorkerThread->start();
    }
    else
    {
        m_pStartTaskBtn->setText(QStringLiteral("Start"));
        m_pWorkerThread->quit();
        m_pWorkerThread->wait();
    }
}
void MainWindow::WorkertResultSlot(void)
{
    qDebug()<<__FUNCTION__<<"threadid"<<QThread::currentThreadId();
}

最后,它将输出这样的结果:

MainWindow::MainWindow mainwindow thread id 0x2bf0
Worker::Worker threadid 0x2bf0
Worker::WorkerTaskStartSlot threadid 0x4af0
MainWindow::WorkertResultSlot threadid 0x2bf0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TaskFinished threadid 0x4af0
Worker::TaskFinished stop timer 0x4af0
Worker::~Worker threadid 0x4af0

相关内容

  • 没有找到相关文章

最新更新