wake-up-neo.com

Wie wird ein Cross-Thread-Signal in Qt ausgegeben?

Qt-Dokumentation besagt, dass Signale und Slots direct, queued und auto sein können.

Es wurde auch angegeben, dass, wenn ein Objekt, dessen Slot sich im Besitz eines Signals befindet, in einem anderen Thread lebt als ein Objekt, dessen Signal sich im Besitz eines Signals befindet, das Aussenden eines solchen Signals der Entsendung einer Nachricht gleicht.

Leider wird in der Dokumentation nicht angegeben, wofür "Leben" steht, und es sind keine Beispiele verfügbar. Ich habe den folgenden Code ausprobiert:

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();
}

Ausgabe ist:

thread 2 started
thread 1 started

MySlot() wird nie aufgerufen :(. Was mache ich falsch?

58
grigoryvp

Es gibt einige Probleme mit Ihrem Code:

  • wie von Evan gesagt, fehlt das Schlüsselwort emit
  • alle Ihre Objekte befinden sich im Hauptthread, nur der Code in den Ausführungsmethoden befindet sich in anderen Threads. Dies bedeutet, dass der MySlot-Slot im Hauptthread aufgerufen wird, und ich bin nicht sicher, ob Sie dies wünschen
  • ihr Slot wird niemals aufgerufen, da die Hauptereignisschleife niemals gestartet wird: Ihre beiden Aufrufe zum Warten () werden erst nach einer sehr langen Zeit abgelaufen sein (und Sie werden wahrscheinlich Ihre Anwendung beenden, bevor dies passiert), und ich glaube nicht Das ist es, was Sie auch wollen, auf jeden Fall haben sie in Ihrem Code wirklich keine Verwendung.

Dieser Code würde höchstwahrscheinlich funktionieren (obwohl ich ihn nicht getestet habe) und ich denke, er macht das, was Sie wollen:

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();
}

Jetzt lebt MyObject in thread2 (dank moveToThread).

MySignal sollte von thread1 gesendet werden (da ich mir nicht sicher bin, könnte es vom Hauptthread gesendet werden, es spielt keine Rolle).

In thread1 wird keine Ereignisschleife benötigt, da das Aussenden eines Signals keine Ereignisschleife benötigt. In thread2 wird eine Ereignisschleife benötigt (von exec () aktiviert), um das Signal zu empfangen.

MySlot wird in thread2 aufgerufen.

46
Aiua

Unterklassen Sie QThread für Qt 4.4+ nicht

Während Aiuas Antwort gut ist, möchte ich auf einige Probleme mit QThread und Qt 4.6 oder 4.7 hinweisen.

Dieser Artikel fasst es zusammen: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/

Fehlende Dokumentation seitens Qt

Leider ist das Problem auf fehlende Aktualisierungen der Dokumentation zurückzuführen. Vor Qt 4.4 hatte QThread keine standardmäßige run () -Implementierung, was bedeutete, dass Sie QThread in Unterklassen unterteilen mussten, um es zu verwenden.

Wenn Sie Qt 4.6 oder 4.7 verwenden, sollten Sie mit ziemlicher Sicherheit nicht die Unterklasse QThread verwenden.

Verwenden Sie moveToThread

Der Schlüssel zum Ausführen von Slots in einem Worker-Thread ist die Verwendung der moveToThread-Methode, wie Aiua betont hat.

36
Will Bickford

du solltest das signal aussenden um deine thread funktion wie zu starten

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

sie können diesem Signal mehrere Argumente hinzufügen

0
kuake56