【发布时间】:2020-04-25 03:59:50
【问题描述】:
QThread 文档提出了两种让代码在单独线程中运行的方法。如果我使用moveToThread 方法,我必须调用processEvents() 来发出超时,以执行lambda。这似乎花费了大量的CPU。为什么会这样?
class Worker : public QObject
{
Q_OBJECT
QTimer* timer;
bool m_abort = false;
public:
Worker() {}
void abort() {m_abort = true;}
public slots:
void run() {
timer = new QTimer;
connect(timer, &QTimer::timeout, []{qDebug() << "computed";});
timer->start(1000);
forever {
if (m_abort) break;
QCoreApplication::processEvents();
}
}
};
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();
};
但是,如果我将 QThread 子类化并重新实现 run(),则无需调用 processEvents。 CPU成本似乎更低。为什么?
class Worker : public QThread
{
public:
Worker() {}
protected:
void run() override {
QTimer timer;
connect(&timer, &QTimer::timeout, []{qDebug() << "computed";});
timer.start(1000);
exec();
}
};
class MainWidget : public QWidget
{
Q_OBJECT
Worker* worker;
public:
MainWidget()
{
worker = new Worker;
worker->start();
}
};
【问题讨论】:
-
恕我直言,调用
processEvents()几乎总是一个错误。通常总会有更好的方法。与嵌套事件循环相同(有时通过使用带有.exec()的对话框间接)。这些都是最终导致 Qt 项目痛苦的事情,应该避免。 -
为什么你需要使用这个
timer以及为什么你需要forever循环用于worker?你搞砸了一些东西,我不知道如何解决它,因为我看不出你到底想要达到什么目的。很可能您根本不需要线程。我怀疑XY problem 所以请提供更多背景信息。请解释为什么你认为你需要一个多线程? -
在我看来,您的第一个解决方案是“忙于等待”。 en.wikipedia.org/wiki/Busy_waiting ... 不是您想做什么!
-
我建议检查 Bo Thorsen 的 QtWS19 threading talk!也许您会找到更好的解决方案。
-
仅供参考,您应该至少使用
std::atomic_bool而不是bool来管理您的循环生命周期。
标签: c++ multithreading qt qthread qtimer