计时器是否从另一个线程启动?

Is the timer being started from another thread?

本文关键字:启动 线程 另一个 是否 计时器      更新时间:2023-10-16

QThread 文档提出了两种使代码在单独线程中运行的方法。如果我子类 QThread 并重新实现 run((,那么我得到

QBasicTimer::start: Timers cannot be started from another thread  

-

#include <QWidget>
#include <QThread>
#include <QBasicTimer>
#include <QDebug>
#include <QEvent>
#include <QCoreApplication>
class Worker : public QThread
{
Q_OBJECT
int id;
bool m_abort = false;
bool compute = false;
public:
Worker() {}
protected:
void timerEvent(QTimerEvent *event) override {
if (event->timerId() == id) {
compute = true;
} else {
QObject::timerEvent(event);
}
}
public slots:
void abort() {m_abort = true;}
void run() {
qDebug() << QThread::currentThreadId();
QBasicTimer timer;
id = timer.timerId();
timer.start(1000, this);
forever {
if (m_abort) break;
QCoreApplication::processEvents();
if (compute)
qDebug() << "computed";
compute = false;
}
}
};
class MainWidget : public QWidget
{
Q_OBJECT
QThread thread;
Worker* worker;
public:
MainWidget()
{
qDebug() << QThread::currentThreadId();
worker = new Worker;
worker->start();
}
~MainWidget(){worker->abort();}
};

1( 计时器是否从另一个线程启动?
2(为什么当QBasicTimer被QTimer替换时,我没有收到警告?
3(为什么我在使用moveToThread时没有收到警告?

#include <QWidget>
#include <QThread>
#include <QBasicTimer>
#include <QDebug>
#include <QEvent>
#include <QCoreApplication>
class Worker : public QObject
{
Q_OBJECT
QBasicTimer* timer;
bool m_abort = false;
bool compute = false;
public:
Worker() {}
protected:
void timerEvent(QTimerEvent *event) override {
if (event->timerId() == timer->timerId()) {
compute = true;
} else {
QObject::timerEvent(event);
}
}
public slots:
void abort() {m_abort = true;}
void run() {
timer = new QBasicTimer;
timer->start(1000, this);
forever {
if (m_abort) break;
QCoreApplication::processEvents();
if (compute)
qDebug() << "computed";
compute = false;
}
}
};
class MainWidget : public QWidget
{
Q_OBJECT
QThread thread;
Worker* worker;
public:
MainWidget()
{
worker = new Worker;
worker->moveToThread(&thread);
connect(this, &MainWidget::start, worker, &Worker::run);
thread.start();
emit start();
}
~MainWidget(){worker->abort(); thread.quit(); thread.wait();}
signals:
void start();
};        

关于第一个(非moveToThread(示例...

快速浏览一下Qt源代码QBasicTimer::start显示以下内容...

void QBasicTimer::start(int msec, QObject *obj)
{
QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance();
// ...
if (Q_UNLIKELY(obj && obj->thread() != eventDispatcher->thread())) {
qWarning("QBasicTimer::start: Timers cannot be started from another thread");
return;
}

因此,它期望其第二个参数obj具有与当前线程相等的线程亲和力。

但是,在您的Worker::run实施中,您...

timer.start(1000, this);

在此上下文中,当前线程是由QThread实例创建的新线程,但this是指MainWidget在主 GUI 线程上创建QWorker的新线程。 因此警告。

编辑 1:

对于问题...

为什么它适用于 moveToThread((?

考虑MainWidgetctor 的实现...

MainWidget()
{
worker = new Worker;
worker->moveToThread(&thread);
connect(this, &MainWidget::start, worker, &Worker::run);
thread.start();
emit start();
}

调用Worker::run时,Worker实例已移动到新线程。 所以当线...

timer.start(1000, this);

执行时,this(指Worker实例(位于当前线程上,并且QBasicTimer::start中的线程关联性测试将在不发出警告的情况下通过。

抱歉,如果上述内容有点复杂,但重要的是考虑第二个参数对QBasicTimer::start的线程亲和力:它必须是当前正在运行的线程。