繁体   English   中英

Qt 线程关联和 moveToThread 的问题

[英]Issue with Qt thread affinity and moveToThread

我试图在 Qt 中使用线程将一些工作委托给一个线程,但我无法让它工作。 我有一个继承 QMainWindow 的类,它有一个成员对象来启动线程来完成工作。 这个对象有 QMainwindow 作为父对象。 它包含并特别初始化另一个 QObject,即m_poller ,我想将其移动到我创建的线程:

m_pollThread = new QThread;
m_poller->moveToThread(m_pollThread);
//Bunch of connection
m_pollThread->start();

我遵循了有关如何在 Qt 中管理线程而不将其子类化(也就是没有做错)的指南,但我仍然在 VS 中收到以下消息:

QObject::moveToThread: 当前线程 (0x2dfa40) 不是对象的线程 (0x120cf5c0)。 无法移动到目标线程 (0x1209b520)

我发现以下帖子似乎处理了相同的问题,但无法使用答案修复我的代码。 我觉得我实际上正确地调用了 moveToThread(因为我不会从另一个线程中调用它来“拉”一个对象到它),但显然我仍然在那里遗漏了一些东西:正如消息提示的那样,似乎已经有多个线程,我对 moveToThread() 的调用似乎以错误的方式结束(尽管我承认我对此完全陌生并且可以弄清楚这是完全错误的......)

那么我使用 Qt 线程的方式可能还有什么问题呢?

谢谢 !

您只能在以下情况下使用moveToThread

  • 您的对象没有父对象(否则父对象将具有不同的线程关联)
  • 您在对象的所有者线程上,因此您实际上是将对象从当前线程“推送”到另一个线程

所以你的错误信息说你违反了第二种情况。 您应该从创建对象的线程调用moveToThread
而且根据你

这个对象有 QMainwindow 作为父对象。

所以 moveToThread 再次不起作用。 您应该从 m_poller 对象中删除父对象

我认为问题在于 m_poller 的初始化,根据错误消息,它似乎被分配给与执行代码片段的线程不同的(第三个)线程。

此外,如果此代码被多次执行,它可能在第一次工作但随后失败,因为 m_poller 不再属于正在执行的线程,而是属于m_pollThread。

您还可以通过从对象的所有者线程执行此操作将其移动到您的线程。

#include <thread>
#include <memory>
#include <condition_variable>
#include <QTimer>
#include <QThread>
#include <QApplication>


template <typename Func>
inline void runOnThread(QThread *qThread, Func &&func)
{
    QTimer *t = new QTimer();
    t->moveToThread(qThread);
    t->setSingleShot(true);
    QObject::connect(t, &QTimer::timeout, [=]()
    {
        func();
        t->deleteLater();
    });
    QMetaObject::invokeMethod(t, "start", Qt::QueuedConnection, Q_ARG(int, 0));
}



void moveToThread(QObject *ptr, QThread *targetThrd=QThread::currentThread())
{
    std::mutex mt;
    std::condition_variable_any cv;
    runOnThread(ptr->thread(),[&]
    {
        ptr->setParent(NULL);
        ptr->moveToThread(targetThrd);
        cv.notify_one();
    });
    cv.wait(mt);
}

你只需要打电话

moveToThread( m_poller, m_pollThread);

如果您通过信号和插槽移动对象(您已经在一个线程中创建了 m_poller 并调用了一个信号并将其传递到另一个不在调用者线程中的对象的插槽),请确保使用Qt::DirectConnection类型connect 通过这种方式,您的插槽将在调用者线程中执行,而调用moveToThread在调用者线程中。

暂无
暂无

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

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