Seite 1 von 1

[gelöst]QThread ohne exec() - keine Signals werden ausgelöst

Verfasst: 29. Mai 2007 11:12
von Konk
Meine kleine Applikation soll über TCP/IP einen Ethernet-RS232-Konverter ansprechen, was in einer "Standalone"-Demo auch sehr gut funktioniert.
Jetzt habe ich eine GUI dazu gebastelt und die Kommunikation in einen separaten Thread ausgelagert. Ich leite von QThread ab und überschreibe die run() Methode. Dort verbinde ich mich mit dem Konverter mittels

Code: Alles auswählen

pTcpSocket->connectToHost("192.168.0.3", 10001);
Wenn ich nun mit

Code: Alles auswählen

QAbstractSocket::SocketState state = pTcpSocket->state();
den Status Abfrage, ist dieser "QAbstractSocket::ConnectingState".
Und da bleibt er auch. Das connected() Signal wird nie ausgelöst.


Folgendes habe ich schon ausprobiert, was aber nicht geholfen hat:

- Den Socket als Membervariable anlegen, statt einer lokalen Variable in run().

- Das connect()

Code: Alles auswählen

connect( &tcpSocket, SIGNAL(connected()), this, SLOT(conEstablishedSlot()));
im Konstruktor meiner abgeleiteten Threadklasse oder in run() platziert.
Da in run() ein neuer Thread erzeugt wird, habe ich auch probiert, statt dem this Pointer einen Pointer auf die Instanz des abgeleiteten Threads zu übergeben. Trotzdem kein Signal.

- Connects mit/ohne Qt::DirectConnection als fünften Parameter.

Das einzige was funktioniert ist, wenn ich in run() die Funktion exec() aufrufe.
Aber wo soll ich dann meine Programmlogik einbauen?
(Es soll alle x Sekunden ein String versendet und einer (über das readyRead() Signal) empfangen werden)

Vielleicht ist auch mein Design verbesserungswürdig.
Wenn jemand eine Idee hat, alles ist herzlich willkommen.

Verfasst: 29. Mai 2007 11:30
von Christian81
exec() startet die Eventloop, also ist es nötig.
Für den Rest - einfach einen QTimer und/oder auf irgendwelche Signals reagieren. Wie im 'normalen' Programm eben auch.

Verfasst: 29. Mai 2007 14:32
von Konk
Danke für die Nachricht.
An Timer hab ich auch schon gedacht, nur wo erstelle ich diesen bzw wie wird er verdrahtet. Mache ich den Timer als Member und will ihn in run() vor exec() starten, sagt Qt:
QObject::startTimer: timers cannot be started from another thread

Erstelle ich den Timer als lokale Variable in run() und möchte dessen Signal mit einem Slot verbinden

Code: Alles auswählen

	QTimer* timer = new QTimer(this);
	connect(timer, SIGNAL(timeout()), this, SLOT(dummySlot()));
	timer->start();
sagt er:
QObject: Cannot create children for a parent that is in a different thread.
Object::connect: No such slot ComThread::dummySlot()
Egal ob ich this oder einen Pointer auf den Thread, der run() aufruft übergebe.

Und wie beende ich den laufenden Thread sauber wieder? Mit terminate() werden angeblich die Ressourcen nicht sauber freigegeben. In meinem Qt Buch ist leider nur ein Thread Bsp ohne exec()-Aufruf.

Verfasst: 29. Mai 2007 14:37
von Christian81
da geht nur QTimer *timer = new QTimer()

this ist im Hauptthread, der timer wird aber im neu erzeugten Thread erstellt -> parent muss im gleichen Thread sein -> deshalb kann der QTimer als parent nicht this haben.

--> QTimer *m_timer als member-Variable, create in run(), delete in dtor

Verfasst: 29. Mai 2007 15:49
von Konk
Ok, aber wie sieht dann der connect aus? Der braucht als dritten Parameter den Receiver. "This" ist der Hauptthread - muss ich also einen Pointer auf diesen übergeben?
z.B.

Code: Alles auswählen

connect(p_timer, SIGNAL(timeout()), m_pMainThread, SLOT(dummySlot()));
Das connect muss im run() stattfinden, außerhalb ist p_timer null.

Wenn ich es so implementiere, sagt Qt zur Laufzeit:
Object::connect: No such slot QThread::dummySlot()
Wie kann ich ihm beibringen welchen Slot er verwenden soll?
Grüße

Verfasst: 29. Mai 2007 15:53
von Christian81
Konk hat geschrieben: Object::connect: No such slot QThread::dummySlot()
Wie kann ich ihm beibringen welchen Slot er verwenden soll?
Indem Du es richtig angibst... :)
m_pMainThread muss schon ein Pointer der Klasse sein, welche den Slot dummySlot() implementiert. So wie es aussieht ist m_pMainThread vom Typ QThread* und/oder deiner Klasse fehlt ein Q_OBJECT

Verfasst: 29. Mai 2007 17:20
von Zandru
Du kannst auch statt exec() regelmässig processEvents() aufrufen.

Verfasst: 29. Mai 2007 19:49
von Konk
Vielen Dank für den Tipp mit processEvents(). Das hab ich in meine Schleife in run() eingefügt, jetzt scheint es alles zu funktionieren.

Zu der anderen Lösung:
pMainThread war ein QThread* - dem fehlte natürlich der Slot. Mit

Code: Alles auswählen

ComThread* m_pMainThread;
im Header und

Code: Alles auswählen

m_pMainThread = this;
im Konstruktor klappt die Verbindung jetzt auch.
Vielen Dank Euch beiden.