Einzelnen Beitrag anzeigen

alkan

Registriert seit: 8. Aug 2008
7 Beiträge
 
#1

Problem beim Zugriff auf TObjectList aus Threads

  Alt 8. Okt 2008, 22:25
Da ich in meinem aktuellen Projekt etliche Probleme mit dem Multithreading habe, habe ich nun ein kleines Testprogramm geschrieben, um dem dem Übel auf den Grund zu gehen. Dabei habe ich eine seltsame Entdeckung gemacht.

Zunächst habe ich einen Sample-Thread geschrieben, der wie folgt aussieht:

Delphi-Quellcode:
TSampleThread= class(TThread)
  TestList: TObjectList;
protected
  procedure Execute; override;
public
  constructor Create; virtual;
end;

constructor TSampleThread.Create;
begin
  inherited Create(False);
  FreeOnTerminate := False;
  TestList := TObjectList.Create;
end;

procedure TSampleThread.Execute;
var j, Rnd: integer;
begin
  j := 1;
  repeat
    Rnd := Random(10);
    inc(j);
  until j = 10;
  Terminate;
end;
Den Thread starte ich nun von einem "Manager" aus, der nichts anderes macht, als bei jedem Aufruf TSampleThread einen freien Slot zuzuweisen und diesen darüber auszuführen. Sind gerade alle 20 Slots besetzt, so wird der Thread nicht ausgeführt.

Delphi-Quellcode:

TThreadManager = class
public
  Thread: array[1..20] of TSampleThread;
  procedure Add;
end;

procedure TThreadManager.Add;
var i: integer; FreeSlot: boolean;
begin
  i := 0;
  FreeSlot := False;
  repeat
    inc(i);
    if Assigned(Thread[i]) = True then
    begin
      if Thread[i].Terminated = True then
        FreeSlot := True;
    end
    else
      FreeSlot := True;
  until (FreeSlot = True) or (i = 20);

  if FreeSlot = True then
    Thread[i] := TSampleThread.Create;
end;
Das ganze klappt bis dahin wunderbar. Auch wenn ich TSampleThread mittels eines TTimer-Objekts durch die Funktion TThreadManager.Add bis zu 1000 Mal pro Sekunde aufrufe, läuft alles wie geschmiert.

Das Problem tritt erst auf, wenn ich im Thread auf ein threadinternes TObjectList-Object zugreife, z.B. auf dessen Eigenschaft Count:

Delphi-Quellcode:
procedure TSampleThread.Execute;
var j, Rnd: integer;
begin
  j := 1;
  repeat
    Rnd := Random(TestList.Count + 10);
    inc(j);
  until j = 10;
  Terminate;
end;
Die einzige Zeile, die ich verändert habe, ist die, wo der Random-Wert bestimmt wird. Ansonsten bleibt alles gleich.
Wenn ich nun aber meinen Thread so wie oben beschrieben sehr oft pro Sekunde ausführe, kommt es früher oder später zum Absturz ("Project1 hat ein Problem festgestellt und muss beendet werden").
Auf den ersten Blick sieht also alles nach einem Synchronizations-Problem aus. Aber daran kann es doch in diesem Fall nicht liegen.
Denn jeder Thread hat sein eigenes TestList-Objekt und greift völlig unabhängig von den anderen exklusiv auf dieses zu!?
Die Threads kommen sich auf keinen Fall beim Zugriff auf TestList in die Quere. Und trotzdem schmiert mein Proggi ab.

Wäre froh um jeden Ratschlag, denn ich finde das ganze einfach zu verwirrend.

Nachtrag: So klappt es...
Delphi-Quellcode:
constructor TSampleThread.Create;
begin
  inherited Create(False);
  FreeOnTerminate := False;
  TestList := TObjectList.Create;
  test := TestList.Count; // = 0
end;

procedure TSampleThread.Execute;
var j, Rnd: integer;
begin
  j := 1;
  repeat
    Rnd := Random(test);
    inc(j);
  until j = 10;
  Terminate;
end;
  Mit Zitat antworten Zitat