QThread moveToThread 不起作用
Posted
技术标签:
【中文标题】QThread moveToThread 不起作用【英文标题】:QThread moveToThread doesn't work 【发布时间】:2017-08-10 07:02:55 【问题描述】:我有一个用于 GUI 的主线程,在其中运行 MainWindow
对象,
在其构造函数中,我创建了一个新的 worker 对象和一个 QThread
对象,然后我将 worker 移动到线程,问题是在打印它们的 id 时它们是相同的:
MainWindow.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();
// ...
worker.cpp
worker::worker(QObject *parent) : QObject(parent)
void worker::initialize()
std::cout << "INITIALIZE " << QThread::currentThreadId() << std::endl;
我明白了:
MAIN_ID 0x7f4009ccb780
INITIALIZE 0x7f4009ccb780
怎么了?
【问题讨论】:
但是,当通过connect SLOT/SIGNAL调用worker类时,打印的ID是不同的 当你直接调用一个函数时,它会在你调用它的线程中运行。 将 initialize() 定义为一个槽,并从 MainWindow 发出一个信号。像这样连接它们:connect(this, SIGNAL(signal_initialize()), pc_w, SLOT(initialize()), Qt::QueuedConnection); 【参考方案1】:答案:moveToThread
确实工作,只是不像你预期的那样。
看起来在调用 pc_w->moveToThread(t_pc)
之后,您希望现在在 t_pc
中调用 pc_w
的所有成员函数。但是,moveToThread()
不是这样做的。
moveToThread()
的目的是更改QObject
“线程亲和性”,换句话说就是对象所在的线程。 但是在基本层面上,它为您提供的一切只是保证通过Qt::QueuedConnection
连接到任何信号的所有对象插槽将在其中调用(运行)特定线程。
成员函数仍然在您调用它们的线程中运行。在您的情况下,您从 GUI 线程调用 initialize()
,因此 QThread::currentThreadId()
为您提供该线程的 id。
我真的建议阅读有关线程事件循环的thread affinity 和this article 的官方文档。
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提出的解决方案人为地将“call initialize()
”事件放入线程事件循环中,达到同样的效果。但是,它不执行任何编译时检查(“initialize”被指定为字符串)。
【讨论】:
【参考方案2】:尝试使用invokeMethod
,而不是直接调用pc_w->initialize()
,例如:
QMetaObject::invokeMethod(pc_w, "initialize", Qt::QueuedConnection);
在这种情况下,您的 initialize()
方法应该是 SLOT 或 SIGNAL。
【讨论】:
以上是关于QThread moveToThread 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 moveToThread() 在 pyqt 中正确使用 QThread?
QThread - 使用 moveToThread 将类成员移动到线程
重点:怎样正确的使用QThread类(注:包括推荐使用QThread线程的新方法QObject::moveToThread)
Qt线程—QThread的使用--run和movetoThread的用法
[QThread]moveToThread()方法创建子线程只能用signal-slot来调用函数
QThread多线程编程经典案例分析(三种方法,解释了为什么使用moveToThread的根本原因,即为了避免调用QThread::exec() )