Hallo,
ich hab da ein ziemliches Problem mit der Synchronisation zweier Threads...
Da es sich bei dem Sourcecode um eine
Unit mit einer visuellen Komponente handelt, geht es einmal um den Programm-(oder
VCL-)Thread und dann einen zweiten "Arbeits"thread, der von der visuellen Komponente genutzt wird.
Hier mal eine beispielhafte - stark verkürzte - Version:
Delphi-Quellcode:
type
[..]
TWorkThread = class(TThread) //Der Arbeitsthread
private
FOwner: TBeispielVC;
[..]
protected
procedure FetchInput_SHARED;
procedure SendOutput_SHARED;
[..]
public
[..]
constructor Create( AOwner: TDosCommand );
end;
TBeispielVC = class(TComponent) //Die visuelle Komponente, die man dem Formular hinzufügt
private
[..]
{ Achtung! Die unteren beiden Variablen ("SHARED") werden von beiden Threads
gleichzeitig benutzt (Datenaustausch). Das Lesen/Ändern (egal von welchem Thread aus)
ergibt zum Teil Zugriffsfehler! }
FInputLines_SHARED: TStringList;
FOutputLines_SHARED: TStrings;
[..]
FSync: TMultiReadExclusiveWriteSynchronizer;
protected
public
constructor Create(AOwner: TComponent); override; //Create-Konstruktor
destructor Destroy; override; //Destroy-Desktruktor
procedure Execute; //Methode um die Verarbeitung zu starten
procedure Stop; //Stoppt (beendet!) die Verarbeitung
[..]
end;
Kurz zur Erlätuerung des des Ganzen:
TBeispielVC ist die visuelle Komponente, die man einem Forumlar hinzufügt. Sie fungiert eigentlich nur als "Einstellungsspeicher" und übernimmt die Steuerbefehle wie Execute (Verarbeitung starten) oder Stop "Verarbeitung abbrechen" usw...
Die visuelle Komponente gehört logischerweise zum Hauptthread der eigentlichen Delphi-Anwendung.
Die wirkliche Verarbeitung übernimmt ein zusätzlich generierter Thread: TWorkThread. Der Hauptcode dieses Threads ist eine repeat until Schleife, die so lange läuft, bis das ganze vom Benutzer über den
VCL-Thread (z.B. mit TBeispielVC.Stop) beendet wird.
-> Das Problem ist der Datenaustausch zwischen den beiden Threads.
TBeispielVC legt die zu übernehmenden Daten in der StringList FInputLines_SHARED (in ihrer eigenen Struktur) ab.
Der Arbeitsthread liest sie dann irgendwann mit der prozedur FetchInput_SHARED aus (wenn er "kann"), kopiert sie in einen eigenen TStringList Puffer und leert dann FInputLines_SHARED - So weiß die VC, dass die Daten übernommen wurden.
Nach dem Verarbeitungsprozess kopiert der Workthread den Output aus einer eigenen TStrings-Liste in die VC-TStrings-Liste FOutputLines_SHARED - per prozedur SendOutput_SHARED. Nach erfolgreichem Abschluss löscht er die Daten in seinem "eigenen" Puffer.
Das passiert wieder und wieder...
Man sieht also: Nur der Workthread liest und schreibt im
VCL-Thread. Der
VCL-Thread selber wartet nur aufs Abholen oder Anliefern der Daten, hat aber mit der Workthread-Struktur nichts zu tun.
Deswegen/Trotzdem kriege ich laufend Zugriffsverletzungen. Ich habe versucht, den Speicherbereich von TBeispielVC durch einnen MultiWreadExclusiveWriteSynchronizer zu schützen (Variable FSync) - ohne viel Erfolg.
Jedesmal, wenn der Workthread in Input_SHARED oder Output_SHARED liest/schreibt, ruft er vorher FOwner.FSync.BeginRead und danach FOwner.FSync.EndRead (oder BeginWrite und EndWrite) auf, aum eine Kollision zu vermeiden.
Auch wenn TBeispielVC die eigenen beiden Variablen Input_SHARED oder Output_SHARED ändert, wird FSync benutzt.
Ich dachte eigentlich, dass sei die Lösung, aber ich habe immer noch schwerste Zugriffsfehler (Absturz von Delphi)!
Jetzt will ich eine TThreadList benutzen, um die beiden Austausch-Variablen in der Struktur von TBeispielVC zu schützen.
Leider habe ich noch nie mit einer solchen Liste gearbeitet und bräuchte etwas Hilfe:
Wo und wie lege ich die ThreadList an und wie schütze ich damit die SHARED-Variablen? Außerdem muss ich ja noch TThreadList.LockList vom TWorkthread aus aufrufen, wenn von daraus in die beiden besagten Variablen geschrieben oder daraus gelesen wird...
Wenn jemand Erfahrung mit sowas hat, wär ne Hilfe sehr nett!
Grüße,
Frank