Seite 1 von 1

QTcpSocket vs. Threads

Verfasst: 6. April 2010 11:59
von Silicomancer
Hi allerseits!

Vielleicht kann mir jemand folgendes erklären... bei den Qt Sockets ist vermerkt, dass sie nicht multi-threading fähig, nur reentrant sind.

Ich würde gerne einen neuen Thread erzeugen, der völlig asynchron zum Main-(GUI-)Thread die Kommunikationsarbeit übernimmt, also empfangene Nachrichten verarbeitet und Antworten verschickt. Der GUI-Thread müßte "lediglich" Zugriff auf den Status des Sockets haben um diesen anzuzeigen.

Jetzt frage ich mich viele verschiedene Dinge.

Wie schaffe ich es, die Klasse Multi-Threading fähig zu machen? Bzw. muss ich das überhaupt? Reicht vielleicht eine Kapselung über Queued-Connections?

Muss das Socket-Objekt vom Netzwerk-Thread erzeugt werden oder kann auch der Main-Thread das Socket-Objekt erzeugen und dem Netzwerk-Thread nur Zugriff zum Empfangen und Verchicken von TCP-Messages geben?

Kann ich so eine Socket-Klasse überhaupt multithreading-fähig machen? Ich könnte den QTcpSocket kapseln und alle von mir benutzten Funktionen mit einem Mutex verriegeln. Aber hilft mir das? Immerhin wird ja, ganz ausser meiner Kontrolle, irgendwo im Hintergrund mit dem Netzwerkadapter kommuniziert. Ist das nicht auch wieder ein anderer Thread? Würde diese Kommunikation nicht mit meinen Netzwerk-Thread konkurrieren?

Wenn ich einen eigenen Netzwerk-Thread benutze, kann ich wohl auf die non-blocking Methoden verzichten und die waitFor...() Methoden benutzen, oder hat das trotzdem Nachteile? Die GUI würde ja nicht mehr blockiert...

Ich habe schon gut funktionierende Threads in Qt geschrieben, aber bisher immer nur mit eigenen Datenverarbeitungsroutinen. Ich bin mir unklar, über die Auswirkungen der Verwendung von Objekten wie den QTcpScokets.

Wäre schön wenn mir jemand helfen könnte, meine Gedanken zu ordnen. Danke!!!

Verfasst: 6. April 2010 12:20
von RHBaum
Die QSocket Dinger sind auf die Verwendung mit der QT getrimmt. Und die QT geht von aus, dass du einen GUI thread hasst, und dich so wenig wie möglich mit anderen threads beschaeftigen willst.

Das heisst die QSocket teile machen die arbeit immer im hintergrund assynchron, also soweiso in nem anderen Thread / Prozess, ob nun von der QT erzeugt, oder vom BS (assynchrone funktionen).

Willst du 100%ige Kontrolle und selber die threadkontrolle übernehmen, machen Dir die QSocket Teile nur Probleme, weil du die nie direkt blockend bekommst, sondern immer nur mit tricks, was zu overhaed fuehrt.
Und du brauchst die Sockets synchron fuer die Eigenverwaltung.

Ich nehm dazu andere bibs oder geh direckt auf die (socket)API (Winsock2 z.b.).
Miest implementier ich soweiso meine Kommunikation QT frei, mit eigenen threads, und nutzt dann nur das Interface von QT Klassen aus, wobei die App von der assynchronietaet dann wenig mitbekommt.

Weiss ned ob s da nicht bessere Loesungen gibt ...

Ciao ...

Verfasst: 6. April 2010 22:49
von Silicomancer
Worüber bist Du denn gestolpert?

Ich habe noch etwas nachgedacht. Nur mal hypothetisch: Wenn die QSockets es vertragen würden, sie komplett in einen Thread zu verfrachten und dort würde man nur die WaitFor...() Funktionen benutzen... das müßte doch eigentlich gehen - oder nicht? Ist es den Sockets nicht egal, welchem Thread sie gehören, solange man nicht mit MEHREREN Threads darauf zugreift (was vielleicht garnicht lösbar wäre, das ist mir im Augenblick völlig unklar) und solange der Heimat-Thread eine Event-Loop hat?

Letztlich steht bei den WaitFor...() Methoden ja sogar dabei, man dürfe sie (wegen Dead-Locks) nur von anderen Threads aus aufrufen - prinzipiell muss es also einen Weg geben, die QSockets mit einem separaten Thread blockierend zu bedienen.

Wobei es bei mir nicht auf Geschwindigkeit ankommt. Ich habe mir schon überlegt den Socket einfach im GUI-Thread zu belassen und an den Netzwerk-Thread per queued Signals/Slots anzubinden. Nachteil wäre hier aber, dass ich die blocking Methoden nicht benutzen kann, das heißt mein Netzwerk-Thread müßte extra Zustände oder Zustandsmaschinen besitzen um auf Netz-Antworten auf seine Netz-Anfragen "warten" zu können.

Verfasst: 7. April 2010 14:14
von RHBaum
prinzipiell muss es also einen Weg geben, die QSockets mit einem separaten Thread blockierend zu bedienen.
Prinzipiell kannst du die synchronitaet der Sockets sicher nachstellen. Nur was du dann bekommst iss folgendes:

Du legst nen thread an, der deine Sockketfunktion anstoesst, die Socketfunktion selber erzeugt wieder nen Thread/prozess, der dir die arbeit abnimmt, du setzt nen SynchronisationElement um deinen Thread blocken/Schlafen zu lassen, der nicht von dir kontrollierte thread weckt deinen dann auf zum weitermachen, und beendet sich sofort wieder.

Klingt nicht toll, iss auch nicht toll .... aber definitiv machbar.
Die Frage stellt sich dann aber nach dem warum ?

Nutzt Du Events um den assynchronen ereignisse ueber den GUI thread durchzuleiten, an nen anderen Thread, der die Daten dann verarbeitet (Achtung raceconditions beachten) ... und das noch parrallel, also assynchton, dann hasst die QSockets genau benutzt wie vorgesehen .... nämlich assynchron. Und deine Welt sollt in Ordnung sein.

Manchmal sind aber Socketoperationen und die zugehoerige verarbeitung ziemlich stark ineinander verzahnt, bzw die verarbeitung so trivial, das eine syncronisation zwischen verarbeitung und socketfunktionen (lesen / schreiben), weil in unterschiedlichen threads, einfach zu viel aufwand machen und sich ned lohnen wuerd. da isses besser man nutzt synchrone socketfunktionen und macht die verarbeitung im selben thread gleich.
Da bist mit den QSockets aufgeschmissen ....
Ich habe mir schon überlegt den Socket einfach im GUI-Thread zu belassen
Genau dafuer sind die dinger ausgelegt. Im GUI thread laeuft der socket definitiv nicht, sondern nur die verwaltung, also er haengt sich in die eventqueue ein (die laeuft sowieso meist mainthrad) und ansonten schiebt er alle aktionen sofort in nen anderen thread/prozess rueber. startet und killt den Socket thread/prozess. Mehr macht nen QSocket/Assynchroner Socket nicht im aufrufenden thread.
Nachteil wäre hier aber, dass ich die blocking Methoden nicht benutzen kann, das heißt mein Netzwerk-Thread müßte extra Zustände oder Zustandsmaschinen besitzen um auf Netz-Antworten auf seine Netz-Anfragen "warten" zu können.
Diesen nachteil hasst du immer sobald du assynchrone funktionen verwendest, egal bei was. Sogar leseoperationen auf nen file kannst du assynchron machen. Und ja du brauchst dann nen rudimentaeren FSM (Zustandsautomat) für.
Das muss aber kein nachteil sein, sondern kann nen vorteil sein. Als nachteil betrachtet man das meist nur, weil man bei assynchronitaet um die ecke denken muss teilweisse, also das einem ned so gelaufig und intuitiv ist, wie die synchrone / blockende Denkweisse.
Wie gesagt, wenn deine Verabreitung nicht trivial iss und parallelisierbar, dann lass lese/schreibe operationen auf dem socket assynchron (im eigenen thread, aber nicht von dir angelegt) laufen und nimm fuer die bearbeitung nen weiteren thread, und lass die sich über nen FSM synchen.
Das ist alles andere als unüblich.
Übrigens, um daten von einem thread in den anderen zu schieben ohne zu kopieren und rcae conditions zu vermeiden, eignen sich automatisch dynamische datenstrukturen mit Besitzsemantik(Quelle/Senke) hervorragend. (leider gehen die ned ueber signal/slots)
Worüber bist Du denn gestolpert?
Meine aussage bezog sich auf den Fall, das man wirklich blockende sockets und verarbeitung in einem thread haben will. Das macht ab und an scho sinn, weil Assynchrone ereignisse zu synchronisieren macht schon bissi aufwand.
und Prioritaeten und so koennen auch eine Rolle spielen. Aber das zaehlt alles unter das grosse kapitel Performance.
Wenn Performance / Laufzeiten keine rolle spielen -> isses eh egal was nimmst und der kuerzere Leidensweg iss meist sich von der verwendeten Umgebung (qt in dem Fall) inspirieren zu lassen !

Ciao ...