Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Kurze Frage zur Thread Sicherheit (https://www.delphipraxis.net/170806-kurze-frage-zur-thread-sicherheit.html)

Klaus01 4. Okt 2012 19:07

AW: Kurze Frage zur Thread Sicherheit
 
Delphi-Quellcode:
procedure TThread.Execute;
begin
  while not Terminated do
  begin
    for I := Low(A) to High(A) do
    begin
      EnterCriticalSection(CS);
      if Use then
      begin
        //hier werden nur Felder von A[I] gelesen und geändert
      end;
      LeaveCriticalSection(CS)
    end;
    Sleep(1);
  end;
end;
Delphi-Quellcode:
procedure TThread.Execute;
begin
  while not Terminated do
  begin
    EnterCriticalSection(CS);
    try
      for I := Low(A) to High(A) do
      begin
        if Use then
          begin
            //hier werden nur Felder von A[I] gelesen und geändert
          end;
      end;
    finally
      LeaveCriticalSection(CS)
    end;
    Sleep(1);
  end;
end;
oder TThreadList verwenden.

Grüße
KLaus

luke2 4. Okt 2012 19:33

AW: Kurze Frage zur Thread Sicherheit
 
So kann ich es nicht machen, da das den Thread nutzlos machen würde. Es werden in der Schleife einige Berechnungen durchgeführt. Dies würde dazu führen, dass der Hauptthread beim Einfügen einfriert.

Aphton 4. Okt 2012 19:55

AW: Kurze Frage zur Thread Sicherheit
 
Der Sinn der Sache ist ja, dass beim Einfügen bzw. Ändern einer Liste kein anderer Thread Zugriff darauf haben sollte.

Medium 4. Okt 2012 21:04

AW: Kurze Frage zur Thread Sicherheit
 
Da sich das Array selbst ja nicht ändert, könnte man hier für jedes Array-Element eine eigene CS (als Record-Member) nehmen. Das Array an sich so ist safe, so lange seine Länge nie verändert wird. Nur kann es dir passieren, dass ein Add() Aufruf nur halb fertig ist, und du ggf. "unfertige" Daten in dem Record hast. Und gaaaaanz selten kann da ggf., grad bei der String-Zuweisung, ein Zugriffskonflikt passieren. Ganz selten, weil du über das Setzen von "use" ganz am Schluss schon ein wenig Sicherheit hast, aber das ist trotzdem ein bischen Spiel mit dem Feuer. Sowas kann wochenlang sauber laufen, und dann wundert man sich (evtl. nach Änderungen, bei denen man nicht an diese besonderen Umstände dachte) woher auf einmal diese grausam schlecht zu debuggenden sporadischen AVs her kommen.

Bei Add() mit Threads wurde ich übrigens hellhörig: Ich hatte mal den Fauxpas begangen, eine einfache TObjectList mit Threads einzusetzen. Dort kann ein Add() ein SetLength() des internen Arrays auslösen, was meinem Thread 1-2x pro Woche (bei einer Anwendung, die 24/7 läuft) seine Daten unterm Poppo weggezogen hat. (Vermutlich öfter, aber der Speicher war wohl meist noch mit gültigem Kram belegt.) Eigentlich so offensichtlich, bei mir aber nach diversen Änderungen über Monate verteilt eingeschlichen, ohne dass ich es bewusst gemerkt habe. Gebranntes Kind scheut das Feuer: Seit dem bin ich mit CriticalSections per du =)

Bummi 4. Okt 2012 22:40

AW: Kurze Frage zur Thread Sicherheit
 
Man könnte dem Thread auch über eine "gelockte" Property mitteilen, wie weit er Save arbeiten kann (ich nehme an er arbeitet in einer Schleife)

luke2 4. Okt 2012 22:56

AW: Kurze Frage zur Thread Sicherheit
 
Medium / Bummi
Danke für die Antworten. Habt ihr evtl. ein ganz kurzes Beispiel wie man es (nur mit TRTLCriticalSection) machen könnte, damit es ganz sicher ist?

Bummi 4. Okt 2012 23:49

AW: Kurze Frage zur Thread Sicherheit
 
Den Setter/Getter der Property mit einer CriticalSection wrappen, im Thread auch nur auf die Property nicht auf die dahinterliegende Variable zugreifen.

Sir Rufo 5. Okt 2012 01:51

AW: Kurze Frage zur Thread Sicherheit
 
Wenn du schon XE2 einsetzt, warum willst du unbedingt mit Arrays arbeiten?
IMHO wäre eine TQueue hier genau richtig. Die Verarbeitung dauert relativ lange (hast du gesagt), dann würde ich auf jeden Fall nicht erst alles abarbeiten und dann zu schauen, ob der Thread evtl. abgebrochen wird, sondern immer nur ein Paket bearbeiten.
Delphi-Quellcode:
TMyThread = class( TThread )
strict private
  FCS : TCriticalSection;
  FQueue : TQueue<TMyRecord>;
protected Execute; override;
public
  procedure Add( ARecord : TMyRecord );
end;

TMyThread.Add( ARecord : TMyRecord );
begin
  FCS.Enter;
  try
    FQueue.Enqueue( ARecord );
  finally
    FCS.Leave;
  end;

TMyThread.Execute;
var
  LRecord : TMyRecord;
  LHasData : Boolean;
begin
  while not Terminated do
    begin
      // Raus aus der Queue
      FCS.Enter;
      try
        LHasData := ( FQueue.Count > 0 );
        if LHasData then
          LRecord := FQueue.Dequeue;
      finally
        FCS.Leave;
      end;

      // Hier bietet sich auch wunderbar ein Event an, da der Thread dann solange schläft
      // bis wieder Daten vorhanden sind, oder der Thread terminiert wurde

      // Wenn keine Daten, dann schlafen und wieder von Vorne
      if not LHasData then
        begin
          Sleep( 1 );
          Continue;
        end;

      // Bearbeiten
      if LRecord.Use then
        ...

      // Rein in die Queue (wenn es denn sein soll)
      if LRecord.Use then
        begin
          FCS.Enter;
          try
            FQueue.Enqueue( LRecord );
          finally
            FCS.Leave;
          end;
        end;
    end;
end;

Furtbichler 5. Okt 2012 07:37

AW: Kurze Frage zur Thread Sicherheit
 
Also ich mach das mit einer Semaphore und einer CS.
Delphi-Quellcode:
Procedure TMyThread.Add(aSomething : TData);
Begin
  FCS.Enter;
  Try
    Queue.Enqueue(aSomething);
    ReleaseSemaphore(FSemaphore,1,nil);
  Finally
    FCS.Leave
  End
End;

Function TMyThread.GetNextData : TData;
Begin
 FCS.Enter;
 Try
   If Queue.Count>0 then
     Result := Nil
   else
     Result := Queue.Dequeue;
 Finally
   FCS.Leave;
 End;
End;
     
Procedure TMyThread.Execute;
Begin
  While not Terminated do
    If WaitForSingleObject(FSemaphore,INFINITE)=WAIT_OBJECT_0 then
      DoWhatever(GetNextData);
end;
Ich sträube mich, einen Thread mit Sleep(1) im Kreis rennen zu lassen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:46 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz