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;