![]() |
CriticalSection nötig ?
Hi Leute,
kurz ne Frage zur CriticalSection: 1. Nehmen wir mal an ich habe innerhalb eines Threads eine private StringListe. 2. Andere Threads können nicht direkt auf die Stringlist zugreifen, sondern nur über den Methode :
Code:
3. Die StringList enthält eine Liste von Befehlen die sequentiell abgearbeitet werden sollen, d. h. neue Befehle am Ende hinzufügen und immer das Element 0 in der liste ist der aktuelle Befehl und wird nach der verarbeitung gelöscht.
procedure TmyThread.add(Command : String);
begin fCmdList.Add(Command); if Suspended then resume; end; 4. Der Execute Coode des Threads sieht folgendermaßen aus :
Code:
So, jetzt meine Fragen :
procedure TmyThread.Execute;
begin repeat while fCmdList.Count > 0 do begin doCommand;; if fChatList.Count > 0 then // nötig ?? sleepEx(100,true); end; // nichts mehr in der Warteschlange --> Thread schlafen legen Suspend; until Terminated; end; Da TStringList ja nicht Thread sicher ist, muss ich hier mit CriticalSection arbeiten ? Obwohl ich von aussen nur immer Elemente am ende der liste hinzufüge ? Wenn ich mit CriticalSection arbeite, dann nur bei Delete der stringliste oder auch beim Add ? Irgentwo hab ich mal gelesen das CriticalSections immer global deklariert werden müssen, damit auch alle threads blockiert werden ?! Ist das richtig ? Kann ich nicht innerhalb meines Threads als private Var eine CS erzeugen ? Ich schütze ja auch nur das add und Delete der ebenfalls internen stringliste. Und der Zugriff geschieht ja nicht direkt von anderen Threads sondern wie oben beschrieben mit der Add-Methode des Threads. Letze und abschliessende Frage : Ist der Construkt im obringen OnExecute praktikabel, um eine Liste in einem Thread abzuarbeiten und wenn nichts zur verarbeitung da ist, soll der Thread schlafen, wenn was hinzugefügt wird soll er aufwachen. Danke, Data |
Re: CriticalSection nötig ?
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Schau mal unter in der OH unter Semaphore und Signal im Zusammenhang von Synchronisationsobjekten nach. Das Szenario, was Du beschreibst, nennt man iÜ ![]() |
Re: CriticalSection nötig ?
Hi,
ich arbeite dann immer mit TThreadList. Das ist der sicherste Weg.
Delphi-Quellcode:
with AThreadList.LockList do // -> TList Thread save
try finally AThreadList.UnLock; end; |
Re: CriticalSection nötig ?
Zitat:
Das Thema Threads hat mehr Fallstricke als die Erzeugung von, Warten auf und Benachrichtigung zwischen ihnen! |
Re: CriticalSection nötig ?
@Choose:
Erstmal danke für Deine Antwort, hat mir schon sehr geholfen. Bei dem Thema Threads gibt es ja auch verdammt viel Lösungsansätze und keiner ist die Patent-Heilmethode :mrgreen: Ich habe Deinen Link zum Thema FiFo-Puffer etwas näher betrachtet, dazu noch eine Frage : Ist das nicht genau das Prinzip, was ich da konstruiert habe ? Die OnExecute-Methode legt sich schlafen, wenn nichts mehr zur Verarbeitung da ist und die Add Methode weckt den Thread wieder auf, falls er schläft. Wo ist der Unterschied ? Gruß Data |
Re: CriticalSection nötig ?
Der Unterschied leigt, wie häufig in der OOP, bei der Zuständigkeit: Den Thread hat es nicht zu interessieren, dass er "schlafen gelegt wird". Auch das Locking sollte nicht in seinen Zuständigkeitsbereich fallen.
Idealerweise ist diese Verhalten vollkommen transparent, etwa in der Form:
Delphi-Quellcode:
bzw
procedure TMyThread.Execute;
var myItem: TMyClass; begin Assert(Assigned(FFifoData), 'FiFo-Buffer not assigned'); while not Terminated do begin myItem:= FFifoData.Pop; DoSthWidth(myItem); end; end;
Delphi-Quellcode:
Das Blockieren eines Clients (Aufrufer), der die Nachricht Pop schickt, sowie dessen anschließende Fortsetzung, sobald ein Element dem Puffer hinzugefügt worden ist, übernimmt nach diesem Muster vollständig der Puffer.
procedure TMyTread.AddItem(const AnItem: TMyClass);
begin if not Assigned(AnItem) then raise EItemNotAssignedError.Create(ItemNotAssigned); Assert(Assigned(FFifoData), 'FiFo-Buffer not assigned'); FFifoData.Push(AnItem); end; Problematisch ist in diesem Zusammenhang lediglich der Fall, dass der Thread beendet werden soll, jedoch kein weiterer Eintrag im Puffer vorhanden ist. Hierfür könnte eine spezielle Methode des Puffers eingesetzt werden, der alle Consumer (den Thread) weckt, ohne ein Element als Rückgabewert von Pop zur Verfügung zu stellen. Denkbar ist der Wurf einer Exeception EBufferClosed, die dann in Execute adequat behandelt werden sollte:
Delphi-Quellcode:
procedure TMyThread.Execute;
var myItem: TMyClass; begin while not Terminated do try myItem:= FFifoData.Pop; DoSthWidth(myItem); except on EBufferClosed do Terminate; end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:51 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