5

我试图在 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 线程的方式可能还有什么问题呢?

谢谢 !

4

4 回答 4

8

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

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

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

该对象以 QMainwindow 作为父对象。

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

于 2013-06-06T11:06:53.767 回答
1

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

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

于 2013-06-06T10:57:22.497 回答
0

如果您正在通过信号和槽移动对象(您已经在一个线程中创建了 m_poller 并调用了一个信号并将其传递给不在调用者线程中的另一个对象的槽),请确保Qt::DirectConnection为您的connect. 这样,您的插槽将在调用者线程中执行,并且调用moveToThread在调用者线程中。

于 2019-08-23T16:17:20.177 回答
0

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

#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);
于 2017-07-02T11:10:30.247 回答