![]() |
Mehrere Container für mehrere Threads?
Hallo,
habe mich vor ein paar Tagen mit einigen aus dem Forum über Container und Threads unterhalten. Ich habe eine Containerklasse und ein Thread-Objekt erstellt. In der Containerklasse befindet sich ein Array, indem Daten vom Thread abgelegt und aufbereitet werden. Das klappt alles wunderbar. Nur jetzt bekomme ich langsam das Problem, dass ich manchmal mehrere Threads gleichzeitig laufen habe, aber immer nur den gleichen Container. Ab un zu kommen Fehlermeldungen. Ich glaube, dass es Probleme gibt, wenn mehrere Threads auf das gleiche Array zugreifen und die Daten schnell nacheinander verändern. Denn das Hauptprogramm soll sich die Daten aus dem Array nehmen und anzeigen. Doch während es die Daten von Thread1 anzeigen möchte, hat Thread2 schon die Daten verändert und eine andere Struktur gespeichert. Nun kommt es zu AVs beim Anzeigen. Nun ist die Frage, ob ich für jeden Thread einen eigenen Container erstellen soll und wann ich ihn dann freigeben soll? Nachteil wäre, dass ich wieder viele globale Container-Variablen habe, denn der Auftrag einen Thread zu erstellen und das Anzeigen der Daten sind in verschiedenen Methoden. Ich hoffe, ihr versteht, was ich meine. Hier mal der Array-Code aus der Container-Klasse:
Delphi-Quellcode:
Danke im Voraus
type
TExpData = Array of String; type TContainer=class(TSimpleRWSync) private FExpData: TExpData; function getExpData(i: Integer): String; function getExpDataCount: Integer; public procedure AddExpData(const Value: String); procedure ClearExpData; property ExpData[i: Integer]: String read getExpData; property ExpDataCount: Integer read getExpDataCount; end; function TContainer.getExpData(i: Integer): String; begin BeginRead; try result:=FExpData[i]; finally EndRead; end; end; procedure TContainer.AddExpData(const Value: String); begin BeginWrite; try SetLength(FExpData, Succ(Length(FExpData))); FExpData[High(FExpData)]:=Value; finally EndWrite; end; end; procedure TContainer.ClearExpData; begin BeginWrite; try SetLength(FExpData, 0); finally EndWrite; end; end; function TContainer.getExpDataCount: Integer; begin result:=High(FExpData); end; |
Re: Mehrere Container für mehrere Threads?
GetExpDataCount solltest du auch in beginread und endread einbauen.
Wenn du nun gleichzeitig aus mehreren Threads Ergebnisse haben möchtest, dann musst du auch mehrere Container erstellen, oder in dem einen einen Container eine Logik entwickeln, dass du z.B. je ThreadID ein eigenes TExpData anlegst. Aber global hast du doch hoffentlich die Container nicht. Du musst den Container im MainThread anlegen. Der Container selbst ist ein Feld vom Mainthread. Und dem Thread übergibst du nur (bspws.: im Constructor) den Container. also nicht als Kopie sondern nur dein Zeiger so wie er ist (einfache Zuweisung). Da kannst du auch verschiedene Container je Thread nehmen. Aber bitte nicht global. |
Re: Mehrere Container für mehrere Threads?
Dein Problem kannst du sehr einfach mit CriticalSections lösen.
Inplementiere eine TCriiticalSection als Feldvariable in deine Thread-Klasse. Immer wenn auf gemeinsam genutzte Dateien, Objekte usw. zugegriffen wird, machts du das innerhalb einer CriticalSection.
Delphi-Quellcode:
... FCriticalSection.Enter; try //Zugriff auf gemeinsam genutzte Objekte, Dateien usw. finally FCriticalSection.Leave; end; ... |
Re: Mehrere Container für mehrere Threads?
Zitat:
|
Re: Mehrere Container für mehrere Threads?
Hm...
mit der Erstellung des Containers habe ich es so gemacht:
Delphi-Quellcode:
Der Grund ist folgender: Die Prozedur StartThread startet den Thread und weist ihm den Container zu. Die Methode CallBack empfängt die Nachricht des Thread, dass er Daten in ExpData geschrieben hat und ruft dann eine entsprechende Prozedur auf, die die Daten anzeigt. Also habe ich zwei Prozeduren, die auf die Daten von "Container" zugreifen und daher Global als Variable von Form4 definiert. Ist das jetzt richtig oder falsch?
var
Form4: TForm4; Container: TContainer; procedure TForm4.FormCreate(Sender: TObject); begin Container:=TContainer.Create; end; procedure TForm4.FormDestroy(Sender: TObject); begin Container.Free end; |
Re: Mehrere Container für mehrere Threads?
Du musst eigentlich keine Variable global definieren. Lege sie doch als Feld in TForm4 hinein.
Startthread und Callback sehe ich nicht. |
Re: Mehrere Container für mehrere Threads?
Erklär mir das bitte nochmal genauer...
Hier nochmal die Methoden für's absenden des Threads und für's Empfangen der Nachrichten:
Delphi-Quellcode:
Achso, und "Machwasmitdaten1" und "Machwasmitdaten2" machen GANZ unterschiedliche Dinge, greifen aber beide auf Container.ExpData[x] zu.
procedure TForm4.StartThread;
var SQL: TSQLThread; begin SQL:=TSQLThread.Create(True); SQL.FreeOnTerminate:=True; SQL.postvars:=False; SQL.FHndl:=Form4.Handle; SQL.DataCode:=1; // Identifiziert LParam, damit ich mit case of arbeiten kann SQL.DataContainer:=Container; SQL.Resume; end; procedure TForm4.CallBack(var msg: TMessage); begin if (msg.WParam = 1) then begin // LParam => Container.DataCode (also mein Identifizierungsmerkmal) case (msg.LParam) of 1: Machwasmitdaten1; 2: Machwasmitdaten2; end; end; end; |
Re: Mehrere Container für mehrere Threads?
Jo ist doch alles super programmiert.
Da brauchst du überhaupt keine globale Variable. Leg sie doch einfach in die Klasse TForm4 rein. So und jetzt musst du dir halt überlegen, ob du für jeden Thread einen eigenen Container machst, oder in den einen Container mehrere TExpDatas. Wann Freigeben? gute Frage: 1. Du schickst eine Message am Ende des SQL-Thread an den Mainthread, der den Container löschen soll 2. Du löschst den Container im onTerminate-Ereignis des Threads (geht nur, wenn du nicht in einer DLL bist; ist aber ansonsten mit Variante 1 gleichwertig) 3. Du nimmst Interfaces. Die Löschen sich selber, wenn sie nicht mehr benötigt werden (Das Interface musst du wahrscheinlich von IReadWriteSync ableiten) |
Re: Mehrere Container für mehrere Threads?
Danke für das Kompliment - hast mir aber auch dabei recht viel geholfen!
Doch das verstehe ich immernoch nicht, wie meinst du das und wie kann ich dann mehrere Instanzen von "Container" haben Zitat:
|
Re: Mehrere Container für mehrere Threads?
Eine Sache sehe ich grade, lass mal das "Form4" vor dem ".Handle" weg.
Variablen gehören entweder als Feld in eine Klasse oder lokal in eine Methode:
Delphi-Quellcode:
type Txy=class(...)
private FConatiner:Tcontainer; //Das ist ein Feld einer Klasse (deswegen so ein F davor) ... public //oder hier, dann kann man auch von außen drauf zugreifen, brauchst du aber nicht end; mehrere Instanzen:
Delphi-Quellcode:
Wobei eine TObjectList anstatt des Arrays bedeutend besser wäre. Und jetzt kannst du für jeden Thread ein Element im Array füllen.
type Txy=class(...)
private FConatiner:array of Tcontainer; //Das ist ein Feld einer Klasse (deswegen so ein F davor) ... public //oder hier, dann kann man auch von außen drauf zugreifen, brauchst du aber nicht end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:03 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-2025 by Thomas Breitkreuz