簡體   English   中英

如何在Qt中發出跨線程信號?

[英]How to emit cross-thread signal in Qt?

Qt 文檔指出信號和槽可以是directqueuedauto

它還指出,如果擁有插槽的對象“生活”在與擁有信號的對象不同的線程中,則發出此類信號就像發布消息一樣 - 信號發射將立即返回,並且將在目標線程的事件循環中調用插槽方法。

不幸的是,文檔沒有說明“生活”代表什么,也沒有可用的例子。 我嘗試了以下代碼:

main.h:

class CThread1 : public QThread
{
Q_OBJECT
public:
    void run( void )
    {
        msleep( 200 );
        std::cout << "thread 1 started" << std::endl;
        MySignal();
        exec();
    }
signals:
    void MySignal( void );
};

class CThread2 : public QThread
{
Q_OBJECT
public:
    void run( void )
    {
        std::cout << "thread 2 started" << std::endl;
        exec();
    }
public slots:
    void MySlot( void )
    {
        std::cout << "slot called" << std::endl;
    }
};

main.cpp:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    CThread1 oThread1;
    CThread2 oThread2;
    QObject::connect( & oThread1, SIGNAL( MySignal() ),
        & oThread2, SLOT( MySlot() ) );
    oThread1.start();
    oThread2.start();
    oThread1.wait();
    oThread2.wait();
    return a.exec();
}

輸出是:

thread 2 started
thread 1 started

MySlot()永遠不會被調用 :(。我做錯了什么?

您的代碼有很多問題:

  • 就像 Evan 所說的那樣,缺少 emit 關鍵字
  • 您所有的對象都存在於主線程中,只有 run 方法中的代碼存在於其他線程中,這意味着將在主線程中調用 MySlot 插槽,我不確定那是您想要的
  • 您的插槽永遠不會被調用,因為主事件循環永遠不會啟動:您對 wait() 的兩次調用只會在很長時間后超時(並且您可能會在此之前殺死您的應用程序),我認為不會這也是你想要的,無論如何它們在你的代碼中真的沒有用。

這段代碼很可能會工作(雖然我沒有測試過),我認為它可以做你想要它做的事情:

class MyObject : public QObject
{
    Q_OBJECT
public slots:
    void MySlot( void )
    {
        std::cout << "slot called" << std::endl;
    }
};

class CThread1 : public QThread
{
    Q_OBJECT
public:
    void run( void )
    {
        std::cout << "thread 1 started" << std::endl;
        int i = 0;
        while(1)
        {
           msleep( 200 );
           i++;
           if(i==1000)
              emit MySignal();
        }
    }
signals:
    void MySignal( void );
};

class CThread2 : public QThread
{
    Q_OBJECT
public:
    void run( void )
    {
        std::cout << "thread 2 started" << std::endl;
        exec();
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    CThread1 oThread1;
    CThread2 oThread2;
    MyObject myObject;
    QObject::connect( & oThread1, SIGNAL( MySignal() ),
        & myObject, SLOT( MySlot() ) );
    oThread2.start();
    myObject.moveToThread(&oThread2)
    oThread1.start();
    return a.exec();
}

現在 MyObject 將存在於 thread2 中(感謝 moveToThread)。

MySignal 應該從 thread1 發送(我不確定那個,它可能是從主線程發送的,這並不重要)。

thread1 中不需要事件循環,因為發出信號不需要事件循環。 在線程 2(由 exec() 啟動)中需要一個事件循環來接收信號。

MySlot 將在 thread2 中調用。

不要為 Qt 4.4+ 子類化 QThread

雖然 Aiua 的回答很好,但我想指出 QThread 和 Qt 4.6 或 4.7 的一些問題。

本文總結: http : //blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/

Qt 方面缺乏文檔

不幸的是,問題源於缺乏對文檔的更新。 在 Qt 4.4 之前,QThread 沒有默認的 run() 實現,這意味着您必須繼承 QThread 才能使用它。

如果你正在使用Qt 4.6或者4.7,那么你幾乎肯定應該繼承的QThread。

使用 moveToThread

正如 Aiua 指出的那樣,讓插槽在工作線程中執行的關鍵是使用 moveToThread 方法。

你應該發出信號來啟動你的線程函數,比如

emit operateCut(examId,examName_examTemplate[examName].studentIdRec,examName_examTemplate[examName].choiceRecA,examName_examTemplate[examName].choiceRecB,examName_examTemplate[examName].objectRecA,examName_examTemplate[examName].objectRecB);

您可以在此信號中添加多個參數

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM