QThread moveToThread 不起作用

QThread moveToThread doesn't work

本文关键字:不起作用 moveToThread QThread      更新时间:2023-10-16

我有一个用于GUI的主线程,其中运行MainWindow对象, 在其构造函数中,我创建了一个新的 worker 对象和一个QThread对象,并将 worker 移动到线程中,问题是在打印它们的 id 时它们是相同的:

主窗口.cpp

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl;
QThread *t_pc = new QThread;
worker *pc_w;
pc_w = new pc_worker();
pc_w->moveToThread(t_pc);
t_pc->start();
pc_w->initialize();
// ...
}

工人.cpp

worker::worker(QObject *parent) : QObject(parent) {
}
void worker::initialize() {
std::cout << "INITIALIZE " << QThread::currentThreadId() << std::endl;
}

我得到:

MAIN_ID 0x7f4009ccb780
INITIALIZE 0x7f4009ccb780

怎么了?

答:moveToThread确实有效,只是没有按照您预期的方式工作。

看起来在调用pc_w->moveToThread(t_pc)后,您希望现在t_pc调用pc_w的所有成员函数。然而,这不是moveToThread()所做的。

moveToThread()的目的是更改QObject"线程亲和性",换句话说,更改对象所在的线程。但在基本层面上,它为您提供的所有内容只是保证通过Qt::QueuedConnection连接到任何信号的所有对象插槽都将在该特定线程中调用(运行(。

成员函数仍在从中调用它们的线程中运行。在您的情况下,您从 GUI 线程调用initialize(),因此QThread::currentThreadId()为您提供该线程的ID

我真的建议阅读有关线程亲和力的官方文档和这篇关于线程事件循环的文章。

QThread* thread = new QThread;
Worker* worker = new Worker;
// Uses Qt::AutoConnection (default)
// which will be transalted into Qt::QueuedConnection
QObject::connect(thread, &QThread::started, worker, &Worker::initialize);
std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl;
worker->moveToThread(thread);
thread->start();

输出:

MAIN_ID 0000000000003E5C
INITIALIZE 0000000000003DAC

trivelt提出的解决方案人为地将"调用initialize()"事件放入线程事件循环中,达到相同的效果。但是,它不执行任何编译时检查("初始化"被指定为字符串(。

尝试使用invokeMethod而不是非常频繁地调用pc_w->initialize(),例如:

QMetaObject::invokeMethod(pc_w, "initialize", Qt::QueuedConnection);

在这种情况下,您的initialize()方法应该是插槽或信号。