Hallo,
In meinem Code sind folgende Klassen:
1. Tconnection_manager
Diese Klasse läuft im Main-Thread.
2. Tconnection_thread
Diese Klasse ist von QThread abgeleitet.
Sie enthält weiterhin ein Attribut das den Pointer
auf auf ein Objekt von Tconnection_manager enthält.
Dieser wird dann an Tconnection weitergereicht.
3. Tconnection
Diese Klasse leitet sich von QTcpSocket ab.
Sie wird in Tconnection_thread::run deklariert (läuft also im eigenen Thread).
Sie besitzt folgende Methoden :
listen()
Diese Methode speichert alle Daten die über den Socket kommen in ein Objekt vom Typ QByteArray.
Wenn keine Daten mehr kommen soll es diese über eine Signal -Slot-Verbindung zu einem Object der Klasse Tconnection_manager weiterreichen.
Der Slot send(QByteArray data)
Wenn dieser Slot ein Signal erhält soll er die Daten des mitgelieferten Arrays versenden.
Ich habe nun folgende Fragen:
1. Ist eine Signal-Slot-Verbindung der Objekt von Tconnection mit Tconnection_manager überhaupt möglich ?
Tconnection ist von QTcpSocket abgeleitet.
In der Dokumentation finde ich folgendes:
"Event driven objects may only be used in a single thread. Specifically, this applies to the timer mechanism and the network module. For example, you cannot start a timer or connect a socket in a thread that is not the object's thread."
Weiter unten steht in der Dokumentation:
"Each thread can have its own event loop. The initial thread starts its event loops using QCoreApplication::exec(); other threads can start an event loop using QThread::exec(). Like QCoreApplication, QThread provides an exit(int) function and a quit() slot.
An event loop in a thread makes it possible for the thread to use certain non-GUI Qt classes that require the presence of an event loop (such as QTimer, QTcpSocket, and QProcess). It also makes it possible to connect signals from any threads to slots of a specific thread. This is explained in more detail in the Signals and Slots Across Threads section below."
Bedeutet dass, das wenn ich Tconnection_thread mit exec() aufrufe und queud connection verwende eine Verbindung von Objekten deren Klassen von QTcpServer abgeleitet sind zu Objekten in anderen Threads doch möglich ist ?
Oder bringe ich da etwas durcheinander ?
2. Wenn ich über eine Signal-Slot-Verbindung, die Objekte in unterschiedlichen Threads verbindet,Daten in Form eines QByteArray Objektes austausche ist dann eine Tiefenkopie (deep copy) erforderlich ?
Was passiert eigentlich mit Objekten , die vor dem Beenden des Threads nicht zerstört wurden ?
Sind nur ihre Ressourcen nicht freigegeben worden und ich kann mit einem Pointer, der auf sie zeigt und den ich zuvor an einen anderen Thread übergeben habe dort mit diesen Objeken weiter arbeiten oder droht ein Absturz ?
Den Artikel über Implicit Sharing habe ich leider nicht verstanden.
3. Ich möchte die Methode (Slot) send(QByteArray data) der Klasse Tconnection mit einem Mutex schützen.
Wo muss ich den Deklarieren ?
Vielen Dank für eure Antworten
[gelöst] Signal-Slot Verbindung über Thread-Grenzen
[gelöst] Signal-Slot Verbindung über Thread-Grenzen
Zuletzt geändert von Bronski am 29. April 2009 12:55, insgesamt 1-mal geändert.
zu 1.
Ja definitiv. Dein Thread, wenn er nur Signale abschickt, braucht nicht mal ne eigene Message Loop. Nur wenn dein Thread auf Signale reagieren soll, (Slots in dem thread laufen sollen) braucht er die.
zu 2.
Je nach anwendungsfall kann es sinnvoll sein oder nicht ....
Das problem, ist eher eine Kopie zu erzwingen. Durch das shared copy (copy on write) kannst du nicht einfach ne Kopie machen, sondern du musst quasi tricksen.
Besser ist das Array selbst zu schuetzen ... und die referenz zu erzwingen (also die kopie zu meiden). Da bist dir 100% sicher was da passiert, andersrum eher nicht, ausser du studierst die internas des QByteArrays.
Ausserdem sollte die Sache mit den referenzen performanter sein.
zu 3.
Den Mutex legst natuerlich da an, wo auch dein QByteArray definiert wird. Alles andere nur ueber referenzen / Zeiger ....
Ciao ....
Ja definitiv. Dein Thread, wenn er nur Signale abschickt, braucht nicht mal ne eigene Message Loop. Nur wenn dein Thread auf Signale reagieren soll, (Slots in dem thread laufen sollen) braucht er die.
zu 2.
Je nach anwendungsfall kann es sinnvoll sein oder nicht ....
Das problem, ist eher eine Kopie zu erzwingen. Durch das shared copy (copy on write) kannst du nicht einfach ne Kopie machen, sondern du musst quasi tricksen.
Besser ist das Array selbst zu schuetzen ... und die referenz zu erzwingen (also die kopie zu meiden). Da bist dir 100% sicher was da passiert, andersrum eher nicht, ausser du studierst die internas des QByteArrays.
Ausserdem sollte die Sache mit den referenzen performanter sein.
zu 3.
Den Mutex legst natuerlich da an, wo auch dein QByteArray definiert wird. Alles andere nur ueber referenzen / Zeiger ....
Ciao ....
Da bin ich anderer Meinung. Sollen in einer Qt-Umgebung Daten (QByteArrays oder andere Container-Klassen mit Implicit Sharing) zwischen Threads getauscht werden, kann dies ohne detailiertes Wissen über die internen Abläufe geschehen:zu 2.
Je nach anwendungsfall kann es sinnvoll sein oder nicht ....
Das problem, ist eher eine Kopie zu erzwingen. Durch das shared copy (copy on write) kannst du nicht einfach ne Kopie machen, sondern du musst quasi tricksen.
http://doc.trolltech.com/4.5/threads.ht ... it-sharingEven in multithreaded applications, you can safely use them as if they were plain, non-shared, reentrant value-based classes.
Wie jede normale Variabel kann also ein QByteArray über eine Signal/Slot-Connection problemlos an einen anderen Thread gesendet werden. Bei gleichzeitigem Zugriff ist (ebenfalls wie bei jeder normalen Variabel) eine Serialisierung (Mutexe) notwendig.
ähnlich wie bei: http://doc.trolltech.com/4.5/qmutex.html#detailsIch möchte die Methode (Slot) send(QByteArray data) der Klasse Tconnection mit einem Mutex schützen.
Einfach ein QMutex als privaten Member.. danach im Slot "m.lock()" und hinterher ".unlock()"...
Vielen Dank für eure schnellen Antworten.
Diese Multithreading-Materie ist völlig neu für mich.
Ich weiß nicht ob ich folgende Dinge richtig verstehe:
1.
thread-sicher bedeuted , dass aus zwei unterschiedlichen Threads zeitgleich auf ein und dasselbe Objekt zugegriffen werden kann.
Das heißt für mich:
An einem Slot können zeitgleich mehrere Signale ankommen - die Serialisierung übernimmt das Objekt(die Klasse) zu dem der Slot gehört.
reentrant bedeuted das eine Funktion(Slot,Methode) aus unterschiedlihen Threads aufgerufen aber zu unterschiedlichen Objekten gehören muss.
Das heißt für mich:
Ein Slot einer Klasse, die reentrant aber nicht thread-sicher ist darf nur Signal zur Zeit empfangen.
Habe ich die Begriffe reentrant und thread safe richtig verstanden ?
2.
Aus der Dokumentation:
Event driven objects may only be used in a single thread. Specifically, this applies to the timer mechanism and the network module. For example, you cannot start a timer or connect a socket in a thread that is not the object's thread.
Heißt daß,das wenn ich ein Ereignis gesteuertes Objekt über Threadgrenzen hinweg verbinde, muss ich zwingend qued connections verwenden, damit auch der Slot in dem Thread ausgeführt wird in dem sein zugehöriges Klassen-Objekt deklariert wurde ?
3.
Aus der Dokumentation:
You must ensure that all objects created in a thread are deleted before you delete the QThread. This can be done easily by creating the objects on the stack in your run() implementation.
Das verstehe ich nicht.
Alle Variablen (Klassen-Objekte etc.) die in einem anderen Thread verwendet sollen werden doch in der Methode run() deklariert. Werden, die nicht automatisch freigegeben wenn run() beendet ist ?
Was passiert mit Speicher, der mit malloc() oder new reserviert , aber nicht freigegeben wurde ?
Kann man wenn man zuvor einen Pointer auf diese Bereiche in einen anderen Thread kopiert hat dort mit diesen Speicher weiterarbeiten ?
Diese Multithreading-Materie ist völlig neu für mich.
Ich weiß nicht ob ich folgende Dinge richtig verstehe:
1.
thread-sicher bedeuted , dass aus zwei unterschiedlichen Threads zeitgleich auf ein und dasselbe Objekt zugegriffen werden kann.
Das heißt für mich:
An einem Slot können zeitgleich mehrere Signale ankommen - die Serialisierung übernimmt das Objekt(die Klasse) zu dem der Slot gehört.
reentrant bedeuted das eine Funktion(Slot,Methode) aus unterschiedlihen Threads aufgerufen aber zu unterschiedlichen Objekten gehören muss.
Das heißt für mich:
Ein Slot einer Klasse, die reentrant aber nicht thread-sicher ist darf nur Signal zur Zeit empfangen.
Habe ich die Begriffe reentrant und thread safe richtig verstanden ?
2.
Aus der Dokumentation:
Event driven objects may only be used in a single thread. Specifically, this applies to the timer mechanism and the network module. For example, you cannot start a timer or connect a socket in a thread that is not the object's thread.
Heißt daß,das wenn ich ein Ereignis gesteuertes Objekt über Threadgrenzen hinweg verbinde, muss ich zwingend qued connections verwenden, damit auch der Slot in dem Thread ausgeführt wird in dem sein zugehöriges Klassen-Objekt deklariert wurde ?
3.
Aus der Dokumentation:
You must ensure that all objects created in a thread are deleted before you delete the QThread. This can be done easily by creating the objects on the stack in your run() implementation.
Das verstehe ich nicht.
Alle Variablen (Klassen-Objekte etc.) die in einem anderen Thread verwendet sollen werden doch in der Methode run() deklariert. Werden, die nicht automatisch freigegeben wenn run() beendet ist ?
Was passiert mit Speicher, der mit malloc() oder new reserviert , aber nicht freigegeben wurde ?
Kann man wenn man zuvor einen Pointer auf diese Bereiche in einen anderen Thread kopiert hat dort mit diesen Speicher weiterarbeiten ?
-
thereapman
- Beiträge: 36
- Registriert: 6. Juni 2007 15:39
@Bronski
zu 1. threadsafe:
Wenn eine Klasse als "threadsicher" deklariert ist, bedeutet das nicht, das sie schon geschuetzt ist. Du musst alle Klassen eigentlich prinzipiell selber schuetzen, auch in der QT, ausser paar Hilfsklassen die sich mit dem Multithreading an sich beschaeftigen, also per definition ohne Multithreading keinen Sinn machen, die schuetzen sich intern scho automatisch (QThreadPool etc).
threadsicher heisst eigentlich nur, das du ueberhaupt technisch die Chance hasst, die Dinger richtig scheutzen zu koennen.
Das stellt paar anforderungen an die Klassen, eine ist zum Beispiel, das sich die Klassen vorausschaubar und definiert verhalten. Das heisst du wissen musst was wann passiert, damit du ueberhaupt schuetzen kannst. Globale/Statische variablen sind ein problem, weil die sind vor dir verborgen, die einzelnen Instzanzen greifen also auf eine gemeinsame instanz zu, die du ned kennst, und wenn die ned selber geschuetzt ist, hasst du keine chance ! Damit hat sich zum beispiel mal die STL Impl von MS (dinkumware) aus dem bereich der multithreadsafe libs geschossen.
Ob QByteArray threadsicher ist, ist ne definitionsfrage.
Da koennte man hier sicher paar leute an den tisch setzen und es wuerde keine gemeinsame Meinung rauskommen.
Im Sinne allgemeiner Multithreading funktionalitaet ist sie es meiner Meinung nach nicht, weil:
Durch das Copy on write kopiert sie die daten an ner unvorhergesehen Stelle. "Richtig" Threadsicher kannst die klasse nur machen, wenn genau weisst wo die kopie gemacht wird. Diese Info findest aber eher im Kleingedruckten, und wird vom Anwender versteckt, weil sie der "naiven" Verwendung von QByteArray auch bissi im Wege steht.
Im Inet gibts ne ganze Menge Abhandlung zum Thema internes cachen, cow im zusammenhang mit multithreading.
Anders sieht es aus, wenn du die von der QT vorgschlagenen Methoden zum Multithreading uebernimmst. Da wird die Situation entspannt.
die Qt erledigt intern viel fuer dich, was zwar ned transparent ist, dir aber ne eher naive verwendung ermöglicht.
Solange du dich in dem bereich aufhaelst, wird ned viel passieren. Aber wehe z.b. du speicherst mal zeiger auf die internas von nem Qbyte array weg, weil den in ner C funktion brauchst etc, dann faellt das kartenhaus zusammen.
Oder wehe, Du bekommst threads aus einem nicht QT context, zb aus ner anderen lib, die keine qt verwendet, dann kannst die QT klassen nimmer so naiv verwenden.
Sicher kann und sollte man dann die QT und deren Container noch verwenden, wenn man sie braucht, aber man sollte halt sehr viel sorgfalt walten lassen.
reentrant:
Ne funktion ist reentrant, wenn sie ablaufinvariant ist, es also keinen unterschied macht, ob sie aus immer nur einen, oder mehreren threads aus aufgerufen wird. Idealer weisse benutzt ne reeintrante funktion nur lokale variablen, die also nur fuer den angesprungen durchlauf gueltig sind. Das schleisst ein new mit ein, wenn die funktion selber das delete beim austritt oder ner anderen geeigneten stelle ausfuehrt.
Genau so sind multithread sichere Klassen, die intern allokierten speicher verwenden (stl container etc) auch moeglich.
Ne nichtreentrante funktion hat meist globale/statische variablen oder Syncmechanismen oder ressourcen, oder andere Nebeneffekte. Das heisst in ner multithread umgebung sind diese funktionen eingeschraenkt nutzbar, das heisst es muessen vorher bedingungen sichergestellt werden (Synchronisation), bevor man sie benutzen darf. Alles was zum Gui Thread gehoert, bei der QT ist z.b. nicht reentrant.
Das sollte ne goldene Regel sein ... auch wenn man in windows bissi tricksen kann. Es macht aber kaum Sinn und bringt auch kaum Vorteile diese regel brechen zu wollen, von daher lieber finger weg, und Regel beachten !
Ciao ...
zu 1. threadsafe:
Wenn eine Klasse als "threadsicher" deklariert ist, bedeutet das nicht, das sie schon geschuetzt ist. Du musst alle Klassen eigentlich prinzipiell selber schuetzen, auch in der QT, ausser paar Hilfsklassen die sich mit dem Multithreading an sich beschaeftigen, also per definition ohne Multithreading keinen Sinn machen, die schuetzen sich intern scho automatisch (QThreadPool etc).
threadsicher heisst eigentlich nur, das du ueberhaupt technisch die Chance hasst, die Dinger richtig scheutzen zu koennen.
Das stellt paar anforderungen an die Klassen, eine ist zum Beispiel, das sich die Klassen vorausschaubar und definiert verhalten. Das heisst du wissen musst was wann passiert, damit du ueberhaupt schuetzen kannst. Globale/Statische variablen sind ein problem, weil die sind vor dir verborgen, die einzelnen Instzanzen greifen also auf eine gemeinsame instanz zu, die du ned kennst, und wenn die ned selber geschuetzt ist, hasst du keine chance ! Damit hat sich zum beispiel mal die STL Impl von MS (dinkumware) aus dem bereich der multithreadsafe libs geschossen.
Ob QByteArray threadsicher ist, ist ne definitionsfrage.
Da koennte man hier sicher paar leute an den tisch setzen und es wuerde keine gemeinsame Meinung rauskommen.
Im Sinne allgemeiner Multithreading funktionalitaet ist sie es meiner Meinung nach nicht, weil:
Durch das Copy on write kopiert sie die daten an ner unvorhergesehen Stelle. "Richtig" Threadsicher kannst die klasse nur machen, wenn genau weisst wo die kopie gemacht wird. Diese Info findest aber eher im Kleingedruckten, und wird vom Anwender versteckt, weil sie der "naiven" Verwendung von QByteArray auch bissi im Wege steht.
Im Inet gibts ne ganze Menge Abhandlung zum Thema internes cachen, cow im zusammenhang mit multithreading.
Anders sieht es aus, wenn du die von der QT vorgschlagenen Methoden zum Multithreading uebernimmst. Da wird die Situation entspannt.
die Qt erledigt intern viel fuer dich, was zwar ned transparent ist, dir aber ne eher naive verwendung ermöglicht.
Solange du dich in dem bereich aufhaelst, wird ned viel passieren. Aber wehe z.b. du speicherst mal zeiger auf die internas von nem Qbyte array weg, weil den in ner C funktion brauchst etc, dann faellt das kartenhaus zusammen.
Oder wehe, Du bekommst threads aus einem nicht QT context, zb aus ner anderen lib, die keine qt verwendet, dann kannst die QT klassen nimmer so naiv verwenden.
Sicher kann und sollte man dann die QT und deren Container noch verwenden, wenn man sie braucht, aber man sollte halt sehr viel sorgfalt walten lassen.
reentrant:
Ne funktion ist reentrant, wenn sie ablaufinvariant ist, es also keinen unterschied macht, ob sie aus immer nur einen, oder mehreren threads aus aufgerufen wird. Idealer weisse benutzt ne reeintrante funktion nur lokale variablen, die also nur fuer den angesprungen durchlauf gueltig sind. Das schleisst ein new mit ein, wenn die funktion selber das delete beim austritt oder ner anderen geeigneten stelle ausfuehrt.
Genau so sind multithread sichere Klassen, die intern allokierten speicher verwenden (stl container etc) auch moeglich.
Ne nichtreentrante funktion hat meist globale/statische variablen oder Syncmechanismen oder ressourcen, oder andere Nebeneffekte. Das heisst in ner multithread umgebung sind diese funktionen eingeschraenkt nutzbar, das heisst es muessen vorher bedingungen sichergestellt werden (Synchronisation), bevor man sie benutzen darf. Alles was zum Gui Thread gehoert, bei der QT ist z.b. nicht reentrant.
Oder noch allgemeiner, new und das zugehoerige delete muessen in der selben uebersetztungseinheit (exe, dll) und in selben thread sein, sonst kommt der speichermanager durcheinander.zu 3.) Wenn du mit new objecte im speicher anlegst musst du die auch mit delete wieder löschen bevor du aus run zurückkommst. S
Das sollte ne goldene Regel sein ... auch wenn man in windows bissi tricksen kann. Es macht aber kaum Sinn und bringt auch kaum Vorteile diese regel brechen zu wollen, von daher lieber finger weg, und Regel beachten !
Ciao ...
[gelöst] Signal-Slot Verbindung über Thread-Grenzen
Vielen Dank.
Das hat mich auf jeden Fall schon mal weitergebracht.
Das hat mich auf jeden Fall schon mal weitergebracht.