QThread kommunikation

Alles rund um die Programmierung mit Qt
Antworten
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

QThread kommunikation

Beitrag von DBGTMaster »

Hallo,

Folgende Situation:

- Habe meinen QThread nun in einer Event- Loop am laufen.
- Der MainThread soll den QThread mitteilen, dass er einen bestimmten Slot aufrufen soll.
- Der MainThread soll warten, bis dieser Slot abgearbeitet ist und je nach Antwort dann weiter arbeiten...

Wie realisiere ich soetwas am besten??

1.) Wie kann ich den QThread mitteilen, dass er einen Slot sofort ausführen soll, ohne dass ich eine Signal, Verbindung herstellen muss? Gibts hierfür eine Methode??
2.) Woher weiß ich, wann dieser Slot fertig ausgeführt wurde??

lG
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: QThread kommunikation

Beitrag von Christian81 »

Gar nicht - Busy Wait im Hauptthread ist nicht wirklich sinnvoll da die komplette GUI blockiert...
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QThread kommunikation

Beitrag von solarix »

Es gibt natürlich auch "traditionelle" Methoden (ohne Qt) dafür, aber ich empfinde die Qt-Variante mit Signal/Slots wesentlich einfacher..Daher: Warum keine (zwei) Signal/Slot-Connections (eine für den Auftrag, eine für das Resultat)? Falls man die GUI in dieser Zeit blockieren möchte, kann das problemlos via QSplashScreen geschehen (wobei man sich dann fragen sollte, wozu überhaupt ein Thread genommen wird):

1. In einem Slot der GUI (z.B. auf Button-Click): QSplashScreen Erstellen und Anzeigen und Signal für Job emitten (an Thread)
2. Im Thread den Job erledigen und das Resultat emitten (an Slot in GUI-Thread)
3. Im Slot der GUI Resultat in Empfang nehmen und QSplashScreen schliessen.

hth..
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QThread kommunikation

Beitrag von DBGTMaster »

Ok, so hab ich mir das auch schon fast gedacht...

Und wie sende ich am besten sofort ein Ereignis, um den Slot im Thread auszuführen??

über QTimer::singleShot(0) ??

lG
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QThread kommunikation

Beitrag von DBGTMaster »

Beim QTimer steh ich nun vor folgendem Problem:

Code: Alles auswählen

QTimer::singleShot(0, tcpThread, SLOT(connectTcpServer(QString,quint16)));
Wie übergebe ich diesen nun die Parameter??
Oder soll ich diese über Methoden setzen (setHostname(), setPort() ), und einen leeren Slot einrichten??
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QThread kommunikation

Beitrag von solarix »

Warum denn keine Signal/Slot-Connection von der GUI zum Thread? Dann musst du in der GUI nur noch emitten...

Hin und wieder nutze ich auch "interne" Signals eines Objektes.. z.B.

Code: Alles auswählen

Thread::Thread(..
{
  connect(this, SIGNAL(job(...)), this, SLOT(...)), Qt::QueuedConnection);
}

void Thread::job(args) {
  emit doJob(args); // Signal/Slot zu sich selbst
}

...
void Gui::btnXyClicked()
{
  thread->job(...);
}
dann entfällt das für die GUI.. ist besonders hilfreich, wenn man mehrere solche "Worker"-Threads hat.

hth..
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QThread kommunikation

Beitrag von DBGTMaster »

Also, wenn ich das nun richtig verstanden habe:

QThread Objekt:

Code: Alles auswählen

class TcpMainThread : public QThread {
public:
void connectTcpServer(QString hostname, quint16 port);
public slots:
void runConnectTcpServer(QString hostname, quint16 port);
signals:
void doConnectTcpServer(QString hostname, quint16 port);
}
Und der Konstruktor:

Code: Alles auswählen

TcpMainThread::TcpMainThread(QObject *parent) :
    QThread(parent)
{

    moveToThread(this);

    // ...
    // ...

    // Eigen- Signale / Slots einrichten...
    // Tcp- Verbindung herstellen:
    connect(this, SIGNAL(doConnectTcpServer(QString,quint16)),
            this, SLOT(runConnectTcpServer(QString,quint16)) );
}
Der MainThread ruft nun die connectToServer() Methode auf, diese wirft ein Signal (doConnectToServer), welches dann wiederrum im eventloop des threads die runConnectToServer() aufruft..

So korrekt :) ?

lG

// Edit: Das einzige, was ich noch änderen werde, ist, dass ich die Signal / Slot- Prozedur in eine eigene Klasse auslagern werde, damit die Thread Klasse selber sich auf das eigentliche konzentrieren kann, um übersicht zu behalten...
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QThread kommunikation

Beitrag von solarix »

ganz genau :wink:

übrigens: QTcpServer ist bereits multithreaded..eigentlich braucht man bei Bedarf nur noch Threads für die einzelnen TCP-Verbindungen, nicht jedoch für den Server...
[EDIT] Moment du scheinst da ja ein Client zu haben.. nicht ein Server. Trotzdem: Für den TCP-Client selbst braucht man übrigens auch nur selten ein Thread (nur dann, wenn das Protokoll sehr aufwendig ist..), weil der auch wieder bereits threaded ist.. :wink:

hth!
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QThread kommunikation

Beitrag von DBGTMaster »

solarix hat geschrieben:ganz genau :wink:

übrigens: QTcpServer ist bereits multithreaded..eigentlich braucht man bei Bedarf nur noch Threads für die einzelnen TCP-Verbindungen, nicht jedoch für den Server...

hth!
Das ganze ist auch kein Server, sondern ein Client... Und diesen Lagere ich in einen eigenen Thread ab, damit dieser in Ruhe seine TCP- Anfragen erledigen kann sowie auf seine Antworten warten usw...

Bin gerade dabei, ein Framework zu bauen, um Tcp und GUI komplett zu trennen :)... Und zwar nach dem Prinzip:

Code: Alles auswählen

    TcpCommand_Login* login = TcpMainThread::instance()->newCommand<TcpCommand_Login>();
    login->setUsername( ui->inputUsername->text() );
    login->setPassword( ui->inputPassword->text() );

    connect(login, SIGNAL(loginDone(TcpCommands::userLoginResponse),
                          this, SLOT(loginDone(TcpCommands::userLoginResponser)));

    login->start();
Und der TcpThread sendet dann den Server die Logindaten, wartet auf die Antwort des Servers, verarbeitet diese und sendet diese der GUI zurück..

lG
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QThread kommunikation

Beitrag von solarix »

DBGTMaster hat geschrieben: Das ganze ist auch kein Server, sondern ein Client... Und diesen Lagere ich in einen eigenen Thread ab, damit dieser in Ruhe seine TCP- Anfragen erledigen kann sowie auf seine Antworten warten usw...
Ja, ich weiss. habe das im [EDIT] berichtig.. Ich wiederhole auch gerne nochmals, dass man QTcpSockets "im Normalfall" (was auch immer das in der Softwareentwicklung bedeutet :D) nicht threaded braucht, weil die Sockets bereits threaded sind. Oder mit anderen Worten: warum soll (m)eine Applikation 2x warten: das erste mal im Qt-Thread und das zweite mal nochmal in (m)einem Thread..

hth!
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QThread kommunikation

Beitrag von DBGTMaster »

solarix hat geschrieben:
DBGTMaster hat geschrieben: Das ganze ist auch kein Server, sondern ein Client... Und diesen Lagere ich in einen eigenen Thread ab, damit dieser in Ruhe seine TCP- Anfragen erledigen kann sowie auf seine Antworten warten usw...
Ja, ich weiss. habe das im [EDIT] berichtig.. Ich wiederhole auch gerne nochmals, dass man QTcpSockets "im Normalfall" (was auch immer das in der Softwareentwicklung bedeutet :D) nicht threaded braucht, weil die Sockets bereits threaded sind. Oder mit anderen Worten: warum soll (m)eine Applikation 2x warten: das erste mal im Qt-Thread und das zweite mal nochmal in (m)einem Thread..

hth!
Hallo,

aber in meinen Anwendungsfall ist threaded einfach nötig, da ich ansonsten meine Anwendung blockieren würde, mein Framework will es einfach so :lol:

Aber danke für deine Hilfe :)
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QThread kommunikation

Beitrag von solarix »

DBGTMaster hat geschrieben: aber in meinen Anwendungsfall ist threaded einfach nötig, da ich ansonsten meine Anwendung blockieren würde
Naja.. genau das wolltest du ja eingangs ("Der MainThread soll warten").. aber belassen wir es dabei, du wirst schon wissen was du brauchst :wink:

Ich hab noch was vergessen:

Code: Alles auswählen

    // Eigen- Signale / Slots einrichten...
    // Tcp- Verbindung herstellen:
    connect(this, SIGNAL(doConnectTcpServer(QString,quint16)),
            this, SLOT(runConnectTcpServer(QString,quint16)) );
Ich würde da explizit "QueuedConnection" nehmen.. vermutlich würde die "AutoConnection" schon funktionieren ("If the signal is emitted from a different thread than the receiving object, the signal is queued"), aber weil du da nichts anderes als eine QueuedConnection brauchst, würde ich das auch explizit wählen.. Ausserdem ist da die Doku IMHO nicht 100% exakt (meint "thread" nun thread-"context" oder -"affinity"?)

hth
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QThread kommunikation

Beitrag von DBGTMaster »

solarix hat geschrieben:
DBGTMaster hat geschrieben: aber in meinen Anwendungsfall ist threaded einfach nötig, da ich ansonsten meine Anwendung blockieren würde
Naja.. genau das wolltest du ja eingangs ("Der MainThread soll warten").. aber belassen wir es dabei, du wirst schon wissen was du brauchst :wink:

Ich hab noch was vergessen:

Code: Alles auswählen

    // Eigen- Signale / Slots einrichten...
    // Tcp- Verbindung herstellen:
    connect(this, SIGNAL(doConnectTcpServer(QString,quint16)),
            this, SLOT(runConnectTcpServer(QString,quint16)) );
Ich würde da explizit "QueuedConnection" nehmen.. vermutlich würde die "AutoConnection" schon funktionieren ("If the signal is emitted from a different thread than the receiving object, the signal is queued"), aber weil du da nichts anderes als eine QueuedConnection brauchst, würde ich das auch explizit wählen.. Ausserdem ist da die Doku IMHO nicht 100% exakt (meint "thread" nun thread-"context" oder -"affinity"?)

hth
Ok, werd ich hinzufügen :=)
lG
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QThread kommunikation

Beitrag von solarix »

Bin gerade zufälligerweise auf genau dieses Detail in der (Thread)-Doku gestossen:
http://doc.qt.nokia.com/latest/threads-qobject.html#signals-and-slots-across-threads hat geschrieben:If the signal is emitted in the thread which the receiving object has affinity then the behavior is the same as the Direct Connection
Also musst du da unbedingt eine QueuedConnection nehmen.. denn die Thread-Affinität ist in deinem Fall die gleiche (der "this"-Pointer (sender) hat die gleiche Affinität wie der "this"-Pointer (Empfänger)). Die daraus resultierende DirectConnection würde jedoch bewirken, dass der Slot im GUI-Thread aufgerufen würde.. nicht das, was du möchtest..

hth!
Antworten