简体   繁体   English

QThread moveToThread不起作用

[英]QThread moveToThread doesn't work

I've a main thread for the GUI, in which is run the MainWindow object, in its constructor I create a new worker object and a QThread object and the i move the worker to the thread, the problem is that when printing their ids they are the same: 我有一个用于GUI的主线程,在其中运行MainWindow对象,在其构造函数中创建一个新的工作程序对象和一个QThread对象,然后将工作程序移至该线程,问题是在打印其ID时,是相同的:

MainWindow.cpp 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.cpp

worker::worker(QObject *parent) : QObject(parent) {

}

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

I get: 我得到:

MAIN_ID 0x7f4009ccb780
INITIALIZE 0x7f4009ccb780

What's wrong? 怎么了?

Answer: moveToThread does work, just not in the way you expected. 答: moveToThread 确实可以正常工作,但并非您所期望的那样。

Looks like after calling pc_w->moveToThread(t_pc) you expected all member functions of pc_w to be called in t_pc now. 貌似打完电话后pc_w->moveToThread(t_pc)你所期望的所有成员函数pc_w在被称为t_pc现在。 However, that is not what moveToThread() does. 但是,那不是moveToThread()所做的。

The purpose of moveToThread() is to change QObject "thread affinity" or in other words thread where an object lives. moveToThread()的目的是更改QObject “线程相似性”,换句话说,就是更改对象所在的线程。 But on the basic level everything it gives you is just the guarantee that all the object`s slots connected to any signal via Qt::QueuedConnection will be invoked (run) in that particular thread. 但是从根本上讲,它所提供的一切只是保证通过Qt::QueuedConnection连接到任何信号的所有对象的插槽Qt::QueuedConnection将在该特定线程中被调用 (运行)。

Member functions still run in the thread you invoke them from. 成员函数仍在您从中调用它们的线程中运行。 In your case, you call initialize() from the GUI thread, so QThread::currentThreadId() gives you the id of that thread. 在您的情况下,您从GUI线程调用initialize() ,因此QThread::currentThreadId()为您提供该线程的ID

I really recommend to read official doc on thread affinity and this article on thread event loops. 我真的建议阅读有关线程相似性的官方文档,以及有关线程事件循环的这篇文章

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();

Output: 输出:

MAIN_ID 0000000000003E5C
INITIALIZE 0000000000003DAC

The solution trivelt proposed artificially puts "call initialize() " event into the thread event loop reaching the same effect. trivelt提出的解决方案是人为地将“ call initialize() ”事件放入线程事件循环中,从而达到相同的效果。 However, it does not perform any compile-time checks ("initialize" is specified as a string). 但是,它不执行任何编译时检查(将“ initialize”指定为字符串)。

Try to use invokeMethod instead of diretly calling pc_w->initialize() , eg: 尝试使用invokeMethod而不是直接调用pc_w->initialize() ,例如:

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

Your initialize() method should be SLOT or SIGNAL in this case. 在这种情况下,您的initialize()方法应为SLOT或SIGNAL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM