QMetaObject::invokeMethod 未在正确的线程中调用

QMetaObject::invokeMethod is not called in the correct thread

鉴于以下情况:

class MyThread : public QThread
{
      Q_OBJECT

   public:

      void run() override
      {
         qDebug() << "Started thread: " << QThread::currentThreadId();
         exec();
      }

   public slots:

      void someSlot()
      {
         qDebug() << "Slot called from thread: " << QThread::currentThreadId();
      }
};
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    qDebug() << "Main thread: " << QThread::currentThreadId();

    MyThread t;
    t.start();

    QMetaObject::invokeMethod(&t, "someSlot", Qt::QueuedConnection);

    return app.exec();
}

我将得到以下输出:

Main thread:  0x7fc24e2f3780
Started thread:  0x7fc245493700
Slot called from thread:  0x7fc24e2f3780

但是,由于 Qt::QueuedConnectionMyThread 实例中的事件循环 运行,我希望插槽在 0x7fc245493700.[=17 中执行=]

我做错了什么?

QThread 对象存在于主线程中,即创建对象的线程中,而不是它所代表的线程中。这在 Qt 文档中明确说明(但遵循正常的 'living'-规则)[1]:

It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots and invoked methods will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.

请查看 QThread 文档以获取此 worker-object 方法的示例。

请注意Qt::QueuedConnection是无关紧要的,因为当调用者和插槽处于不同线程时它会自动排队[2]:

Qt::AutoConnection (Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.