【问题标题】:QThread moveToThread doesn't workQThread moveToThread 不起作用
【发布时间】: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);

标签: c++ multithreading qt qthread


【解决方案1】:

答案:moveToThread确实工作,只是不像你预期的那样。

看起来在调用 pc_w-&gt;moveToThread(t_pc) 之后,您希望现在在 t_pc 中调用 pc_w 的所有成员函数。但是,moveToThread() 不是这样做的。

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

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

我真的建议阅读有关线程事件循环的thread affinitythis 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-&gt;initialize(),例如:

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

    在这种情况下,您的 initialize() 方法应该是 SLOT 或 SIGNAL。

    【讨论】:

      猜你喜欢
      • 2012-12-18
      • 2021-07-17
      • 2018-11-10
      • 2013-10-15
      • 2013-12-17
      • 1970-01-01
      • 2014-06-12
      • 2017-01-28
      • 2015-07-31
      相关资源
      最近更新 更多