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.