簡體   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