2016-12-01 4 views
1

Ich habe zwei Objekte, die in verschiedenen Threads lebt und ich versuche herauszufinden, ob ein verwendetes Muster Thread-sicher ist oder nicht.Thread-Sicherheit des Aufrufs von QObject-Methode von einem anderen (nicht-qt) Thread?

Das erste Objekt ist QObject-abgeleitet und lebt (wurde in erstellt) der Haupt-Qt-Thread. Die Klasse enthält einige Q_INVOKABLE Methoden, die von QML aufgerufen werden sollten, einige signal*() Methoden definiert als signals: und einige Emit*() (normale) Methoden, die ich als Wrapper zum Emittieren von Signalen verwenden. Zum Beispiel:

void MyQObjectClass::EmitStatus(void) { 
    emit signalStatusChange(_status); 
} 

Normalerweise höre ich für diese Signale in QML. Das zweite Objekt ist nicht QObject-abgeleitet und lebt in einem zweiten Thread (pthread). Dieser Thread führt seine eigene Ereignisschleife (libev) aus und löst Ereignisse aus. Ich kann nichts in Verbindung mit Qt in diesem Thread verwenden, da ich die benutzerdefinierte libev Ereignisschleife brauche. Für dieses Objekt habe ich einige Notify*() Methoden definiert, die asynchrone Ereignisse über libev senden, um von Rückrufen abgeholt zu werden.

Ich muss in der Lage sein, zwischen den zwei Objekten/Threads zu kommunizieren, aber ich bin nicht sicher, wie man das sicher macht.

Das eigentliche Design ist es, das pthread Thread-Objekt rufen Sie die verschiedenen Emit*() Methoden direkt, so dass das QObject die Informationen ordnungsgemäß an Qt/QML propagieren kann. Wenn ich Informationen von Qt/QML an das pthread/libev Objekt senden muss, rufe ich (vom Qt-Thread) die Methoden Notify*().

Wenn Accessing QObject Subclasses from Other Threads lesen, heißt es:

QObject und alle ihre Unterklassen sind nicht Thread-sicher. Dies umfasst das gesamte Ereignisliefersystem.

aber dann weiter heißt es, dass:

Auf der anderen Seite, können Sie sicher Signale von Ihrem QThread :: run() Implementierung emittieren können, da das Signal Emission Thread-sicher ist.

Also meine Frage ist, ist das oben beschriebene Design thread-sicher? Kann ich sicher anrufen myQObject->EmitMySignal(), die wiederum emit signalMySignal() aufrufen, alles aus dem pthread Objekt?

+0

Ich denke, Sie sollten dies mit 'postEvent' umgehen, anstatt direkt auf das' QObject' zuzugreifen. 'postEvent' ist threadsicher und wurde für diesen Zweck entwickelt, wenn Sie keine normale Signal/Slot-Verbindung verwenden wollen oder können. – Resurrection

+0

Emitting-Signal ist Thread-Safe, wie angegeben. Das Lesen des Werts der Elementvariablen ist jedoch nicht Thread-sicher. Sie müssen also den Zugriff auf '_status 'schützen, wenn auf mehrere Threads zugegriffen wird. Das Aufrufen einer * QObject * -Methode aus mehreren Threads ist fehleranfällig. Wenn Sie das tun, empfehle ich ein paar Dinge: 1. Teilen Sie die Methoden in "von anderen Threads" und "normale" Methoden und haben Sie eine eindeutige Namenskonvention * diese. 2. Unterteilen Sie die Member-Variablen auf die gleiche Weise und stellen Sie sicher, dass der Zugriff auf Member-Variablen, die aus mehreren Threads verwendet werden sollen, mutex-geschützt ist. 3. Überprüfen Sie den Code! – hyde

Antwort

0

Ich werde zeigen, wie zu erreichen, was Sie mit Ereignissen wollen anstelle von Signalen und Slots, die Sie nicht verwenden können (weil eine Seite nicht QObject abgeleitet ist)

class MyObjectClass : public QObject 
{ 
    Q_OBJECT 
public: 
    virtual bool event(QEvent *event) override 
    { 
     bool result = true; 

     if(event->type() == QEvent::User+1) 
      emit signalStatusChange(_status); 
     else 
      result = QObject::event(event); //call direct parent's event here! 

     return result; 
    } 
}; 

Und in der anderen Thread Sie dies tun:

MyObjectClass *p; //holds pointer to the instance in main thread 
qApp->postEvent(p, new QEvent(QEvent::User+1)); 

Dies wird den Zeiger auf die App abrufen, die im Hauptthread lebt und das Ereignis an seine Ereignisschleife sendet. Das Ereignis wird asynchron vom Aufruf verarbeitet. Das Verhalten unterscheidet sich jedoch von dem, was Sie gerade tun. Aber es wird sicherer und imho eleganter. Sie können so viele Typen hinzufügen, wie Sie benötigen. Vergessen Sie nicht, das Ereignis an das Elternobjekt weiterzugeben, wenn Sie es nicht behandelt haben!

Verwandte Themen