![]() |
Synchronisierung von Subthreads (VCL) + Pointerzugriff
Hallo Leuts,
ich hab mal eine kleine Frage: Ich habe einen VCL-Thread dem ich (als Beispiel) einen Zeiger auf einen Boolan-Wert übergeben habe. So, nun einige Frage (insbesonderen an den Thread-Experten v.D. Luckie *g*): Kann ich einfach auf diesen Boolean-Wert aus dem Thread zugreifen? Wenn nein, wie kann ich das ganze Synchronisieren? Ich weis wie ich normale Prozeduren und Funktionen untereinander Synchronisiere, aber hier müsste ja eine Thread-Interne Prozedur Synchronisiert werden ... oder geht das genauso mit Synchronize??? EDIT: Und wenn wir schon dabei sind ... wie sieht das ganze mit einem TMemoryStream aus? Auf diesen wird allerdings !garantiert! nicht vom Hauptthread zugegriffen! (wird von mir gelockt) Aber das wars noch nicht, ich habe noch einen weitere Frage ... Wie kann ich zwei Nebenthreads miteinander Synchronisieren, ohne über den Hauptthread zu gehen? Diese beiden Thread sollen nämlich miteinander kommunizieren. mfG Markus |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Hallo,
eine Möglichkeit wären CriticalSections. Such mal in der Hilfe nach ![]() Gruß xaromz |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Für was? Den Variablenzugriff, den Threadzugriff oder beides ... ach ja, ich wusste gar nicht, dass das auch bei VCL geht^^.
mfG Markus |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Hallo,
Zitat:
// Anmerkung: Deshalb sollten diese Befehle auch sehr sparsam verwendet werden und der Code dazwischen kurz und effizient sein. Zitat:
Gruß xaromz |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Zitat:
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
So, noch eine Frage: Wie sieht die sache aus, wenn ich 100% sicherstellen kann,dass kein Zugriff auf die Eigenschaft erfolgt?
Kann ich dann darauf verzichten? Das Problem ist ganz einfach, dass ich einen TMemoryStream in eine Klasse im Hauptthread habe, die u.a. diesen Stream verwaltet. Eine leistungsintensive Aufgabe habe ich in einem seperaten Thread ... und dieser soll auf den MemoryStream zugreifen. Kann ich in dem Fall auf TCriticalSections verzichten? Die Klasse blockiert jeden Zugriff auf den Stream (von Auserhalb) während der Threadlaufzeit. mfG Markus |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Hallo,
Zitat:
Zitat:
Besser ist es immer, sich abzusichern. Und Fehler zu debuggen, die auf solche Konstrukte zurückzuführen sind, wünsch' ich meinem ärgsten Feind nicht :zwinker: . Gruß xaromz |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
OK, das gehört zum Klassendesign, dass immer nur eine Aufgabe ausgeführt wird, solange wird ein Lock gesetzt, damit nicht verändert wird.
So noch eine wichtige Frage: Wie sieht das ganze bei einer Synchronisierung von zwei Subthreads untereinander aus? Muss das TCriticalSections dort auch als globale Variable vereinbart sein? Oder reicht es, wenn es in der Thread-Klasse des Kind-Threades als public vereinbart wird und somit dem Mama-Thread zu verfügung steht? Eine kurze Struktur meiner Idee: Hautpthread || Mama-Thread mit uses ClassKind-Thread | Kind-Thread mit TCriticalSections als Public Funktioniert das? mfG Markus |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
So, noch eine Frage (nach der obigen, die noch nicht beantwortet ist):
Wie sieht die Sache umgekehrt aus? Wie greift der Hauptthread auf den Nebenthread zu? Critical Sections? Hat der Hauptthread auch ein Synchronize, oder muss ich hier zu Fuß Synchronisieren? mfG Markus |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Gemeinsam verwendete Resourcen/Variablen etc. sollten für den Zugriff grundsätzlich gekapselt werden, so etwa:
Delphi-Quellcode:
Wenn Du das als Get/Set-Methoden einer Eigenschaft implementierst, ist der Zugriff darauf sicher. Zum Verständnis: Eine Critical Section hält nicht etwa alle anderen Threads an, sondern sorgt dafür, das ein zweiter Aufruf von myCS.Enter so lange wartet, bis der erste Aufrufer myCS.Leave aufgerufen hat. Der erste Aufruf von myCS.Enter schließt sozusagen eine Tür von *innen*. myCS.Leave öffnet sie wieder.
Procedure ThreadsafeSetValue (aMyValue : TSomeType);
Begin myCS.Enter; Try fValue := aMyValue; // Na ja, fValue.Assign bei Objekten Finally myCS.Leave; End End; Procedure ThreadsafeGetValue (Var aMyValue : TSomeType); Begin myCS.Enter; Try aMyValue := fValue; Finally myCS.Leave; End End; |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Das bedeutet, dass ich wieder ein TCriticalSections als Globale Variable brauche?
Und wenn ich zwei Subthreads aufeinander Zugreifen lasse? Brauche ich dann auch ein globales Critical Section? Oder reicht es, wenn ich es bei einem Thread als public deklariere und dessen Unit per Uses einbinde? mfG Markus |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Es ist egal wie du es machst, aber die Threads müssen das selbe CriticalSection Objelt benutzen, damit eine Synchronisation stattfindet.
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Du musst Dir überlegen, in wessen Kontext die Variable lebt.
Wenn z.B. Thread1 irgendetwas deklariert, verwendet oder kontrolliert, dann packst Du die Eigenschaft in Thread1:
Delphi-Quellcode:
Oder du deklarierst Dir eine eigene Klasse, die den threadsicheren Zugriff implementiert. Das würde ich empfehlen, wenn die Eigentusverhältnisse nicht eindeutig geklärt sind. Alles eine Frage der Sichtweise: Die Implementierung ist in jedem Fall ähnlich. :stupid:
Type
TMyThread = Class (TThread) Private fMyCS : TCriticalSection; Public Property MyValue : TSomeType Read GetValue Write SetValue; End; ... |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Vielen Dank,
ich denke, ich werd das Objekt in den Unter-Unter-Thread Packen, welcher bei den beiden anderen über uses eingebunden ist --> Zugriff auf das public-Objekt var csMan : TCriticalSection sollte möglich sein ... wenn nicht, bitte warnen *g* mfG Markus |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
So, mir ist gerade noch eine ganz neue Idee gekommen ...
Ist es möglich, eine ganz normale Klasse einfach zu einenm Thread umzumodden? Kann ich dann auf dessen Methoden zugreifen, und wenn ja, werden die dann im Hauptthread oder im Subthread ausgeführt? BTW: Was passiert nach dem Execute? Ich meine, wenn der Code abgearbeitet ist, und kein FreeOnTerminate aktiviert ist? Ist der Thread dann Suspended? In welchem Zusand befindet er sich dann? mfG Markus |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
*push*
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Wenn du nur auf einen 1-, 2-, oder 4-Byte-Wert zugreifen willst, dann sollte es keine Probleme geben, wenn diese zur selben Zeit ausgelesen werden, nur beim ändern mußt du aufpassen, aber eventuell hilft da auch schon ein kurzer Umschalter in den SingelThreadModus.
Var B: ByteBool; auslesen wie immer z.B.
Delphi-Quellcode:
Und das Setzen
If B Then ...
Delphi-Quellcode:
//B := True;
ASM LOCK MOV &B, $FF End; //B := False; ASM LOCK MOV &B, 0 End; |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Könntest du mir kurz erklären, was dieser Code macht/bedeutet? Ich kann leider (noch) kein ASM ...
Ach ja, die anderen Fragen in den Posts 14 und 15 "dürfen" auch beantwortet werden *g* ansonsten, Danke! mfG Markus |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Im Grunde sind es jeweils 2 Befehle.
Dieses kopiert den Wert/Inhalt von x2 nach x1
Code:
Hier also den Wert $FF in den Speicherbereich der Variable B.
MOV x1, x2
Code:
Wobei das obere nur die Kurzfassung ist, ausfühlich würde es so aussehn, wobei B eigentlich ein Pointer (hier ist es ein BYTEPoinTeR) zu einem bestimmten Speicherbereich ist:
MOV &B, $FF
Code:
Das LOCK ist ein Befehl, welcher die CPU für den nachfolgenden Befehl in einen Singlethreadmodus schaltet, es wird also sozusagen nur der nachfolgende Befehlausgeführt, während die anderen threads warten ... somit kann also kein anderer Thread wärend dieser Zeit Befehl ausführen, welcher zu dieser Zeit eventuell auch auf deisen Speicherbereich zugreifen könnte (es läuft ja schließlich Keiner)
MOV BYTE PTR &B, $FF
MOV BYTE PTR [Pointer], $FF also
Delphi-Quellcode:
oder
LOCK MOV BYTE PTR &B, $FF
Delphi-Quellcode:
setzt alle Bits (ist beim ByteBounter halt besser) auf 1 und somit auf TRUE, ohne daß zur selben Zeit ein anderer Thread auf B zugreifen kann.
LOCK MOV &B, $FF
Darum kann man auch ganz normal lesend auf B zugreifen, ohne das es Probleme gibt. |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Danke!
EDIT: Zitat:
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Das würde mich auch interessieren, wollte gerade einen Beitrag dazu schreiben...
also *PUSH* LG, ich |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Wenn du den Schreib-/Lesezugriff innerhalb einer Klasse gegenseitig vor gemeinsamen Zugriff irgendwie (gibt ja mehrere Möglichkeiten) (b)locks, dann kannst du sie auch ohne Probleme von mehreren Thread aus ansprechen.
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
War das die Antwort auf das hier, dann steh ich nämlich auf der Leitung...
Zitat:
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
upps, da hab'sch wohl was falsch verstanden (also keine klasse für threads ummodden)
aber zu deiner Frage sollte es doch was geben ... ist in Delphi nicht schon 'ne Thread-Klasse drin? |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Nein, ich meine man hat irgendeine mehr oder weniger komplexe Klasse, die manchmal etwas länger braucht. Damit das Programm dabei nicht einfriert, und man z. B. den Vorgang abbrechen kann, wäre es gut, das ganze in einen Thread zu verpacken. Das war die Frage - zumindest so wie ich sie verstanden und dann auch "weitergefragt" hab...
LG, ich |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Zitat:
Eine Klasse braucht nicht lange, ein Task braucht lange. Eine Klasse in einen Thread auslagern zu wollen zeugt davon, irgendwas noch nicht vollständig verstanden zu haben. Nur mal angenommen mit jeder Methode, die aufgerufen wird, wird ein Kindthread abgespalten und die Methode dort ausgeführt. Der Methodenaufruf würde dann sofort zurückkehren. Und wann zerstörst du das Objekt? Nachdem der Call zurückkehrt? Damit reißt du dem Thread das Objekt, auf das er arbeitet, unter den Füßen weg. Wartest du auf das Beenden des Threads? Dann hast du auch nichts gewonnen, weil du blockierend wartest oder mit ProcessMessages() periodisch die Nachrichtenschleife abarbeitest, und das kannst du auch direkt im Task machen. Gar nicht? Dein Anwender wird es dir danken. Thread-Modelle und Klassenmodelle beißen sich prinzipbedingt. Das leuchtet ein, wenn man beispielsweise Äpfel mit Birnen vergleicht. Ein Thread ist ein Scheduler-Element, das die zeitliche Verarbeitung von Code regelt. Eine Klasse ist ein logisches, vollständig abstraktes Element, das Daten und Code beinhalten kann, und zwar Code mit mehreren Einsprungpunkten (viele Methoden). Es ergibt wenig Sinn, eine abstrakte Informationsgliederung in eine zeitliche Regelung zu packen, es würde ja ohnehin nichts passieren. Das Problem, vor dem du stehst, ist nicht, daß deine "Klasse lange braucht", sondern daß dein Task lange braucht. Die Lösung des Problems hast du in eine Klasse gekapselt, aber die Klasse alleine führt noch nicht den Task aus. Also mach es richtig und lagere den Task in einen Thread aus, und nicht die Lösung des Problemes. Starte einen Thread und führe in ihm den Code aus, der das Objekt instanziert, initialisiert, den Task erledigt und wieder ordentlich aufräumt. Am Ende kannst du eine Message an den Hauptthread schicken, um in dessen Kontext den Anwender über das Ergebnis des Tasks zu benachrichtigen. Zitat:
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Ja, das ist mir (zumindest nach dem Lesen :mrgreen: ) schon klar, es geht im Konkreten um eine von IdFTP abgeleitete Komponente. Nachdem ja das Verbindungs-Aufbauen etc. länger braucht und dann das Formular einfriert, möchte ich alle Kommunikation mit dem Server in einem eigenen Thread machen. Jetzt gibt es die eine Möglichkeit, in einer von TThread abgeleiteten Klasse alle wichtigen Funktionen (Connect, aber auch Put, Get etc.) nochmals zu deklarieren und dort dann die Parameter in Feldern zwischenspeichern und dann eine Variable auf 'connect' oder einen bestimmten Index setzen, die die Execute-Prozedur in einer while-Schleife immer wieder abfragt und demnach dann die Connect-Funktion der IdFTP-Klasse aufruft.
Gibt es da dann eine bessere Methode? :roll: LG, ich |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Zitat:
Den Thread starten und ihm eine Message-Loop verpassen. GetMessage() ist synchron und blocking, also vergeudest du damit nichtmal Ressourcen, selbst wenn es auf den ersten Blick nach Polling aussieht. Für ein Beispiel brauchst du dir nur ein beliebiges nonVCL-Programm anzuschauen. Dem Thread postest du mit PostThreadMessage() deine Messages, und dieser arbeitet sie ab. Die Message-Queues arbeiten in-order, das heißt du ganz erstmal eine Connect- und eine Get-Message abschicken, die Get-Message wird bearbeitet, sobald das Connect fertig ist. Der Thread reagiert also auf jede Nachricht, die er bekommt, dein Hauptthread läuft aber weiter. Damit die Oberfläche etwas davon mitgekommt, was der Thread gerade tut, kann der Thread ebenfalls Nachrichten an deinen Haupt-Thread (oder besser: irgendein Fenster, dann hast du Unterstützung durch Delphis message-Schlüsselwort), in denen er mitteilt, daß gerade die Verbindung etabliert wurde oder daß er gerade x Bytes empfangen hat und sie dort und dort hinterlegt sind, damit der Thread die empfangenen Daten entgegennehmen kann. Kurzum: Alles, was du bei normaler IPC anwendest, kannst du auch bei prozessinternen Threads anwenden, oft ist es nicht verkehrt. |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Aha! Aber gibt es auch was einfacheres, außer jetzt alle Methoden nochmals zu implementieren? Also dass man das gleich für alle Methoden einer Klasse macht? Anscheinend nicht - oder doch :coder2:
LG, ich Edit: Oder gibt es wenigstens eine Möglichkeit, einen Pointer auf die Methode und einen Pointer auf alle Parameter zu speichern und die Methode mit Parametern nachher so aufzurufen? |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
@Frickeldrecktuxer_TM ... ich habe die Thread-Materie sehr wohl verstanden.
Und ich habe mir gedanken gemacht, bevor ich diese Frage stellte ... in meinem Programmkontext macht das Auslagern ganzer Klassen Sinn, damit der Benutzer mit anderen Programmteilen arbeiten kann, während sich meine Thread-Klassen-Hybrid selbst verwaltet und nach der Ausführung auf die nächste Aufgabe wartet ... Ich habe meinen Grund für diese Idee ... aber danke für die Antworten (und an Gerhard Pfister danke fürs Pushen, ich hatte den Thread schon beerdigt ...) mfG Markus *einbisschensauer* EDIT: @Gerhard ... vielleicht kapselst du den Thread in ein Objekt, welches den Statues des Threads kontrolliert und bei Bedarf an das Hauptprogramm weiterleitet ... als eine Art Dolmetscher ... oder Vermittler |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Zitat:
Schnell zusammengetippt und daher mit 100%iger Wahrscheinlichkeit die falschen Bezeichner, aber die kannst du ja in der Online-Hilfe nachschlagen, sieh mir nach, daß ich als Gelegenheits-mit-Delphi-Entwickler nicht alle Klassen der VCL auswendig kenne ;-)
Delphi-Quellcode:
Und damit die Handler wissen, was zu tun ist, solltest du die die beiden Datenfelder einer Message anschauen. Das sind zwar nur zwei LongWords, aber du kannst einen Pointer zu einem Integer casten, deswegen kannst du beliebig viele Informationen übergeben, indem du einfach einen Record deklarierst, die Daten dort reinpackst und einen Pointer auf den Record an die Nachricht hängst. Casten ist zwar weder schön noch hübsch, aber bei einer C-API, wie Windows nunmal eine hat, leider nicht immer zu vermeiden.
type
TSomeThread = class(TThread) // ... private FIDIrgendwas: TIDIrgendwas; end; constructor TSomeThread.Create(...); begin inherited; FIDIrgendwas := TIDIrgendwas.Create; end; procedure TSomeThread.MessageHandler(Message: TMessage); // oder so begin case Message.MsgType of // oder so STM_CONNECT begin FIDIrgendwas.Connect(...); // fertig, schicke eine Benachrichtigung an den Hauptthread end; STM_GET begin FIDIrgendwas.Get(...); // fertig, schicke eine Benachrichtigung an den Hauptthread end; end; end; procedure TSomeThread.Execute(...); begin // Nachrichtenschleife end; |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Gut, danke!
Und was gehört dann in die Execute-Methode hinein? Ich habe das mal aus einem nonVCL-Proggy herausgekramt, leider aber nicht von mir selber geschrieben :mrgreen:
Delphi-Quellcode:
Übrigens in der Hilfe zu PostThreadMessage steht folgendes:
var
Msg: TMsg; begin while GetMessage(Msg, 0, 0, 0) do begin TranslateMessage(Msg); DispatchMessage(Msg); end; Zitat:
LG, ich Edit: Tippfehler |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Zitat:
Eine Klasse, bei der jeder Methodenaufruf einen weiteren Thread abspaltet funktioniert einfach nicht ohne weiteres. Was aber geht, ist, durch *manuelle* Synchronisierung lediglich *einen* Thread zu verwenden. Das ist das, was ich eben geschildert habe. Das erfordert allerdings entsprechenden Aufwand, um ein Interface aufzubauen. Und man benötigt immer noch zusätzlichen Kontrollcode. Man lagert also nicht die Klasse (oder den Code der Klasse) in einen Thread aus, sondern man lagert die *Benutzung* in einen Thread aus. Diese Benutzung hat man vorher bereits in seinem einzelnen Haupt-Thread, man lagert also effektiv Code aus diesem Haupt-Thread aus, und lässt nicht einfach Aufrufe in einen Thread münden. Nimm zum Beispiel einen Code, der aus einem UCS-16LE-Text einen UCS-16BE-Text (16bit pro Zeichen, Little Endianness gegen Big Endianness) macht. Man kann einen TFile-Stream nehmen und, 2 Bytes einlesen, die Reihenfolge tauschen und die 2 Bytes zurückschreiben. Das Lesen und Schreiben, das wahrscheinlich am längsten dauert (falls nicht, macht man's mit 'nem Diskettenlaufwerk, dann dauert's lange :mrgreen:), in asynchronen Aufrufen zu machen, indem man TFileStream entsprechend modifiziert, würde wahrscheinlich schnell sehr viele Threads erzeugen, die alle noch dabei sind, ihre 2 Bytes zu schreiben. Das Resultat wären jede Menge konkurrierende Laufwerkszugriffe, das kann niemand wollen. Stattdessen lagere ich die Benutzung von TFileStream in einen Thread aus, also den gesamten Vorgang: Lesen, Vertauschen, Schreiben. Dadurch sind alle Operationen in "richtiger" Reihenfolge. Aber ich habe nicht die Klasse ausgelagert, sondern die Benutzung. Zitat:
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Zitat:
Zitat:
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Gut, Danke! :thumb:
Dann sind meine Fragen so weit geklärt... LG, ich |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Ich danke auch ... ich habe aber ein etwas anderes Anwendungsgebiet als Indy
mfG Markus PS: So wie du (Frickeldrecktuxer_TM)mir das vorgschlagen hast, hatte ich das auch umgesetzt ... mir ist der Umbau nur praktischer vorgekommen ... hat aer auch Nachteile. |
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Zitat:
|
Re: Synchronisierung von Subthreads (VCL) + Pointerzugriff
Achja, das habe ich übersehen, aber jetzt ist es klar...
Auch wenn es noch immer nicht ganz funktioniert (gibt noch eine AV)... aber das werde ich mir etwas später anschauen; habe gerade meinen Rechner frisch neu aufgesetzt (der Beitrag kommt schon vom neuen System :mrgreen: ). Wahrscheinlich habe ich irgendwo einen Denkfehler eingebaut... LG, ich |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:43 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz