![]() |
Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Hallo!
Ich habe in meinem Programm eine globale Instanz eines Threads laufen mit einer TObjectList drin. Bei dem Thread handelt es sich um eine Art Verarbeitungs-Queue, in der Aufgaben in Form von Items abgelegt und vom Thread dann verarbeitet werden. Auf die Thread-Instanz greifen mehrere andere Threads zu und zwar ausschließlich mit dem Ziel, der TObjectList neue Objekte (Aufgaben) hinzuzufügen. Dafür ist eine public-deklarierte Funktion innerhalb des Threads vorgesehen. Reicht es in diesem Fall aus, wenn ich nur die TObjectList mit einer TCriticalSection (beide innerhalb der Objekt-Instanz deklariert) schütze oder sollte ich bereits die Zugriffe auf die eingenliche Thread-Instanz mit einer global deklarierten TCriticalSection synchronisieren? Als ich die Klasse erstellt habe, habe ich mir gedacht, dass auf die eigentliche Thread-Instanz eher nur lesend zugegriffen wird und erst die TObjectList geschützt werden sollte. Ist es überhaupt richtig, die Liste innerhalb eines Threads zu erstellen und die dann mithilfe eier public-Funktion zu beschreiben oder wäre es besser, die Liste und die CriticalSection als globale Objekte zu deklarieren und dem Thread nur die Abarbeitung der Aufgaben anzuvertrauen? Aktuell sieht es so aus bei mir:
Delphi-Quellcode:
type
TapDataReceiverQueueItem = class private FClientData: string; FTarget: TapDataTarget; FPriority: TapPriority; public property ClientData: string read FClientData write FClientData; property Target: TapDataTarget read FTarget write FTarget; property Priority: TapPriority read FPriority write FPriority; end; type TapDataReceiverQueue = class(TThread) constructor Create(CreateSuspended: Boolean); destructor Destroy; override; private FQueue: TObjectList; FcsQueue: TCriticalSection; protected procedure Execute; override; procedure DeleteFromQueue(AIndex: integer); public procedure AddToQueue(AClientData: string; ATarget: TapDataTarget; APriority: TapPriority); function Count: integer; end; var DataReceiverQueue: TapDataReceiverQueueItem; implementation ... constructor TapDataReceiverQueue.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); NameThreadForDebugging(ClassName, ThreadID); FQueue := TObjectList.Create(true); FcsQueue := TCriticalSection.Create; end; destructor TapDataReceiverQueue.Destroy; begin if Assigned(FQueue) then FreeAndNil(FQueue); if Assigned(FcsQueue) then FreeAndNil(FcsQueue); DataReceiverQueue := nil; inherited Destroy; end; procedure TapDataReceiverQueue.Execute; var QueueItem: TapDataReceiverQueueItem; begin while not Terminated do begin if (Count > 0) then begin if PERF_DATA_RECEIVER_THREADS_COUNT < PERF_DATA_RECEIVER_THREADS_MAX_VALUE then repeat try if Assigned(FQueue.Items[0]) then try QueueItem := TapDataReceiverQueueItem(FQueue.Items[0]); TapDataReceiver.Create(false, QueueItem.ClientData, QueueItem.Target, QueueItem.Priority); finally DeleteFromQueue(0); end; except end; until (Terminated) or (Count = 0) or (PERF_DATA_RECEIVER_THREADS_COUNT >= PERF_DATA_RECEIVER_THREADS_MAX_VALUE); end; Delay(1); end; end; procedure TapDataReceiverQueue.AddToQueue(AClientData: string; ATarget: TapDataTarget; APriority: TapPriority); var Item: TapDataReceiverQueueItem; begin Item := TapDataReceiverQueueItem.Create; Item.ClientData := AClientData; Item.Target := ATarget; Item.Priority := APriority; FcsQueue.Enter; try FQueue.Add(Item); finally FcsQueue.Leave; end; end; procedure TapDataReceiverQueue.DeleteFromQueue(AIndex: integer); begin FcsQueue.Enter; try FQueue.Delete(AIndex); finally FcsQueue.Leave; end; end; function TapDataReceiverQueue.Count: integer; begin Result := FQueue.Count; end; |
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Ich habe ein ähnliches Szenario wie du und bin immer gut mit
Delphi-Quellcode:
klar gekommen.
TThread.Queue()
Soweit ich weiß legt Queue alles im Stack ab und dann wird der Stack nach und nach abgearbeitet. |
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zitat:
Delphi-Quellcode:
wird der Stack sequentiell verarbeitet.
TThread.Queue()
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Ok daran habe ich nicht gedacht.
Demnach bringen mehrere Threads mit derselben Aufgabe rein gar nicht, wenn man mit Queue alles in den Stack legt. Dann müssen wohl die Profis ran :stupid: Andererseits... du fügst doch nur Einträge in eine ObjectList hinzu. Die eigentliche Arbeit findet doch woanders statt. Dann sollte Queue doch eigentlich doch kein Problem sein. |
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zitat:
Zitat:
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zitat:
Delphi-Quellcode:
an. Der ist genau für solche Zwecke gedacht. Du kannst dort einen
TThreadPool
Delphi-Quellcode:
einstellen und Tasks queuen. Der Pool arbeitet dann alle Aufgaben ab, aber erstellt nie mehr gleichzeitige Threads als angegeben (ist btw. auch deutlich performanter, da Thread Creation zumindest unter Windows einen ziemlichen Overhead hat und der ThreadPool die Threads wiederverwendet).
MaxThreadCount
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zitat:
Es gibt ein s.g. vordefinierter DefaultPool. Von dem kann man die Zahl der Threads abrufen, die problemlos gleichzeitig laufen können. Gilt dieser Wert für das gesammte System oder nur für die aktuelle Anwendung? Ist es sinnvoll, einen eingenen ThreadPool zu erstellen? |
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zitat:
Delphi-Quellcode:
oder
AddToQueue()
Delphi-Quellcode:
absichern?
Count()
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Count ist doch nur lesend. Ich denke da muss man nix absichern.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:41 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