First of all, I\'m still familiarizing myself with multi-threading, and don\'t know much terminology. I need to make sure I\'m doing this right, because it\'s a sensitive su
As explained by @NGLN etc, you need to pool some threads and accept that the easiest way to manage thread numbers is to divorce the actual number of threads from the desired number. Adding threads to the pool is easy - just create some more instances, (passing the producer-consumer task input queue as a parameter so that the thread knows what to wait on). If the desired number of threads is less than that currently existing, you could queue up enough 'poison-pills' to kill off the extra threads.
Don't keep any list of thread pointers - it's a load of micro-management hassle that's just not necessary, (and will probably go wrong). All you need to keep is a count of the number of desired threads in the pool so you know what action to take when something changes the 'poolDepth' property.
The event triggers are best loaded into the jobs that are issued to the pool - descend them all from some 'TpooledTask' class that takes an event as a constructor parameter and stores it in some 'FonComplete' TNotifyEvent. The thread that runs the task can call the FonComplete when it's done the job, (with the TpooledTask as the sender parameter) - you don't need to know what thread ran the task.
Example:
unit ThreadPool;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, contnrs, syncobjs;
type
TpooledTask=class(TObject)
private
FonComplete:TNotifyEvent;
protected
Fparam:TObject;
procedure execute; virtual; abstract;
public
constructor create(onComplete:TNotifyEvent;param:TObject);
end;
TThreadPool=class(TObjectQueue)
private
access:TcriticalSection;
taskCounter:THandle;
threadCount:integer;
public
constructor create(initThreads:integer);
procedure addTask(aTask:TpooledTask);
end;
TpoolThread=class(Tthread)
private
FmyPool:TThreadPool;
protected
procedure Execute; override;
public
constructor create(pool:TThreadPool);
end;
implementation
{ TpooledTask }
constructor TpooledTask.create(onComplete: TNotifyEvent; param: TObject);
begin
FonComplete:=onComplete;
Fparam:=param;
end;
{ TThreadPool }
procedure TThreadPool.addTask(aTask: TpooledTask);
begin
access.acquire;
try
push(aTask);
finally
access.release;
end;
releaseSemaphore(taskCounter,1,nil); // release one unit to semaphore
end;
constructor TThreadPool.create(initThreads: integer);
begin
inherited create;
access:=TcriticalSection.create;
taskCounter:=createSemaphore(nil,0,maxInt,'');
while(threadCount