unit Unit1;
{$mode objfpc}{$H+}
interface
uses
//
type
{ TMyMThread }
TMyMThread = class(TThread)
{custom procedures}
procedure DoM(ParamThreadNumber: integer);
private
//other private variables
fForceTerminate: boolean;
procedure CopyImage;
procedure ShowStatusY;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: boolean; ParamThreadNumber:integer);
procedure InitTerminate;
// other properties
property ForceTerminate:boolean read fForceTerminate write fForceTerminate;
end;
{ TForm1 }
TForm1 = class(TForm)
// classic variables and procedures
private
//other variables
MThreads : array of TMyMThread;
public
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TMyMbrotThread }
constructor TMyMThread.Create(CreateSuspended: boolean; ParamThreadNumber:integer);
begin
Self.ThreadNumber:=ParamThreadNumber;
Self.ForceTerminate:=false;;
inherited Create(CreateSuspended);
end;
procedure TMyMThread.Execute;
begin
// init all thread specific properties
Self.FreeOnTerminate:=true;
Self.DoMB(Self.ThreadNumber); //Main worker procedure
Self.Terminate;
Self.Free;
end;
procedure TMyMThread.InitTerminate;
begin
//setting the thread flag, telling it must exit the procedure called by Execute
Self.ForceTerminate:=true;
end;
procedure TMyMThread.CopyImage;
// this method is only called by Synchronize(@ShowStatus)
begin
//I am copying here a temp image
end;
procedure TMyMThread.ShowStatusY;
// this method is only called by Synchronize(@ShowStatus)
var pos: int64;
begin
//example of how to update a progressBar array to see the % of work performed by each thread on a separate progressbar
//iy is the Y worked by the thread, myiymax is the height of the image on the main form, passed as parameter to the thread
pos:=100*iy div Self.myiymax;
Form1.MProgress[Self.ThreadNumber].Position:=pos;
Form1.MProgress[Self.ThreadNumber].Hint:='Thread #'+IntToStr(Self.ThreadNumber)+ ' progress: '+pos.ToString+'%';
end;
procedure TMyMThread.DoM(ParamThreadNumber: integer);
const
//
var
//
begin
MyImage:=TBitmap.Create;
for localiy := 1 to myiymax do
begin
// make computations for y
for localix := Self.myixmin to Self.myixmax do
begin
//check if one must terminate early
if Self.ForceTerminate then
begin
MyImage.Destroy;
Self.Terminate;
Exit;
end;
// make computations for x and draw pixels on the image
MyImage.Canvas.Pixels[ix-Self.myixmin,iy]:=$FFFFFF div maxiteration*iteration;
//MyImage.Canvas.Pixels[ix-myixmin,iy]:=$FFFFFF - iteration*1000;
end;
//tell the main form how much work was done, sync for Y
Self.Synchronize(@ShowStatusY);
end;
Self.Synchronize(@CopyImage);
MyImage.Destroy;
end;
{ TForm1 }
//all other TForm1 procedures
procedure TForm1.BitBtn2Click(Sender: TObject);
var
i:integer;
begin
//clicking on the execution button leads to the creation of the threads
for i:=Low(MThreads) to High(MThreads) do
begin
MThreads[i]:=TMyMThread.Create(False, i);
//Starting the thread calls in fact its Execute method.
//Thread properties should not be assigned values here, in the main thread
//but in the thread's execute method instead
MThreads[i].Start;
end;
end;
//FormCloseQuery asks if the form may be closed
//without terminating all the threads while they were still working, the form did not close
//so I had to kill by force all the threads, like this:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
i:integer;
begin
//send forceful termination flag
for i:=Low(JThreads) to High(JThreads) do
begin
//Check Assigned to avoid setting a property for a thread that is nil
if Assigned(MThreads[i]) then
MThreads[i].InitTerminate;
Application.ProcessMessages;
// nil the thread
MThreads[i]:=nil;
end;
// Wait for all threads to terminate, if they exist
for i:=Low(JThreads) to High(JThreads) do
begin
if Assigned(MThreads[i]) then MThreads[i].WaitFor;
end;
//Tell the form it may close now
CanClose:=true;
end;
end.