Einzelnen Beitrag anzeigen

alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#3

Re: x Threads die gemeinsam eine Task-Liste abarbeiten, wie?

  Alt 27. Jan 2007, 10:29
Entweder Du implementierst ....
...eine threadsichere Liste, aus der sich die Threads bedienen, oder
...eine Jobliste, die die Jobs in ihrer Execute-Methode an wartende Threads eines Threadpools verteilt.

Ich würde die zweite Variante nehmen. Die 'Add'-Methode der TJoblist fügt den Job in eine Liste ein und erhöht einen threadsicheren Zähler (Semaphore). Die Execute-Methode wartet auf die Semaphore und verteilt das erste Element (LIFO-Prinzip) auf den nächsten freien Thread.

Delphi-Quellcode:
Procedure TJobList.AddJob (aJob : TJob);
Var
  L : TList;

Begin
  L := fJobList.LockList;
  Try
    L.Add (aJob);
    ReleaseSemaphore (fSemaphore,1,nil); // Oder so ähnlich
  Finally
    fJobList.UnlockList;
  End;
End;

Procedure TJobList.Execute;
Var
  L : TList;
  nextJob : TJob;

Begin
  While not Terminated do
    If WaitForSingleObject (fSemaphore,INFINITE) = WAIT_OBJECT_0 Then Begin
      L := fJobList.LockList;
      Try
        nextJob := L[0];
        If PassJobToNextPendingThread (nextJob) Then
          L.Delete(0)
        else
          ReleaseSemaphore (fSemaphore,1,nil); // Semaphore wieder erhöhen, das kein Thread gefunden wurde.
      finally
        fJobList.UnlockList;
      End;
    End;
End;
Jeder Thread, der einen solchen Job ausführen soll, meldet sich bei der TJobList an.

Der Konstruktor der TJoblist könnte diese Threads auch selbst erzeugen (Maximale Anzahl als Parameter im Konstruktor). Alle Threads sind zunächst erstmal in Wartestellung ('Suspended').

Die Methode 'PassJobToNextPendingThread' sucht nun einfach den nächsten (oder ersten) freien Thread und übergibt den Job. Wenn ein Job vermittelt wurde, liefert die Funktion 'TRUE', sonst 'FALSE'. Der Thread beginnt seine Arbeit (ist also nicht mehr in Wartestellung). Der nächste eingehende Job wird dann einfach an den nächsten Thread vermittelt.

Delphi-Quellcode:
Constructor TJoblist.Create (aMaxThreads : Cardinal);
Var
  i : Integer;

Begin
  Inherited Create (True);
  fJoblist := TThreadList.Create;
  fThreadList := TList.Create; // Of TMyThread;

  For i:=1 to aMaxThreads do
    fThreadList.Add (TMyThread.Create (True)); // Alle Threads warten erstmal
  fSemaphore := CreateSemaphore (nil,0,maxint,nil);
  Resume;
End;

Destructor TJobList.Destroy;
Begin
  CloseHandle (fSemaphore);
  ClearThreadList;
  ClearJobList;
  fJobList.Free;
  fThreadList.Free;
End;

Function TJobList.PassJobToNextPendingThread (aJob : TJob);
Var
  i : Integer;

Begin
  For i:=0 To fThreadList.Count - 1 do
     If Not (TMyThread(fThreadList[i]).Suspended then Begin
       TMyThread(fThreadList[i]).Job := aJob;
       TMyThread(fThreadList[i]).Resume;
       Result := True;
       Exit;
     End;
  Result := False;
End;
So, es fehlt nur noch der TMyThread.

Ach ja, alles ungetestet und runtergerasselt. Wer Fehler findet, kann sie behalten.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat