1) Ok I've removed direct VCL access in the thread for TTimer an TLabel. I look at some samples and now I'm using task.comm to send notifies at the form to update the labels.
2) I've tried to use Task.SetTimer but it is never fired. Look at code below: in the loop inside the DoIT procedure I can update the labels only if send manually the MSG_NOTIFIY every "n" (=10000) iterations. Paradoxically, in this case, VCL TTimer works. Maybe I'm doing something wrong.
3) As you can see in the code below, I can get the program work only clicking on button1 in which I simulate an execution without the pool. If I click button2, where I tried to schedule the tasks in a pool, I always get the program locked. Maybe there is something that I didn't realize well in waitforall and maybe there is a better way to achieve my goal.
The complete code is:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, OtlComm, OtlTask, OtlTaskControl, OtlThreadPool;
const
MSG_NOTIFY = WM_USER;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
waitGroup : IOmniTaskGroup;
wk1,wk2,wk3 : IOmniTaskControl;
public
procedure MsgNotify(var msg: TOmniMessage); message MSG_NOTIFY;
procedure DoCreateTasks;
procedure DoSometingAfterFinished;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TMyTask = class(TOmniWorker)
protected
FLbNum : Integer;
FMax : Integer;
FCounter : Integer;
function Initialize: boolean; override;
public
constructor Create(lbNum,Max : Integer);
procedure DoTimer;
procedure DoIT;
end;
function TMyTask.Initialize: boolean;
begin
Result:=inherited Initialize;
if Result then
task.SetTimer(1,500,@TMyTask.DoTimer);
end;
procedure TMyTask.DoIT;
var
ary : array[0..1024] of Byte;
I : Integer;
NF : HFILE;
begin
FCounter:=0;
NF:=FileOpen('file.bin',fmShareDenyNone);
try
for I:=1 to FMax do begin
FCounter:=I;
// !!! only un-commenting this instructions I got the label updated = the timer is never fired !!!
// if (I mod 10000)=0 then
// Task.Comm.Send(MSG_NOTIFY,[FLbNum,FCounter]);
if Task.Terminated then
Break;
FileSeek(NF,0,0);
FileRead(NF,ary,1024);
end;
finally
FileClose(NF);
end;
end;
constructor TMyTask.Create(lbNum,Max : Integer);
begin
FLbNum:=LbNum;
FMax:=Max;
end;
procedure TMyTask.DoTimer;
begin
Task.Comm.Send(MSG_NOTIFY,[FLbNum,FCounter]);
end;
{TForm1}
procedure TForm1.Button1Click(Sender: TObject);
begin
// execution without pool
DoCreateTasks;
wk1.Join(waitGroup).Invoke(@TMyTask.DoIt);
wk2.Join(waitGroup).Invoke(@TMyTask.DoIt);
wk3.Join(waitGroup).Invoke(@TMyTask.DoIt);
waitGroup.RunAll;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
// execution with pool
DoCreateTasks;
wk1.Unobserved.Join(waitGroup).Invoke(@TMyTask.DoIt).Schedule;
wk2.Unobserved.Join(waitGroup).Invoke(@TMyTask.DoIt).Schedule;
wk3.Unobserved.Join(waitGroup).Invoke(@TMyTask.DoIt).Schedule;
waitGroup.WaitForAll;
// I need all tasks finieshed here!
DoSometingAfterFinished;
end;
procedure TForm1.DoCreateTasks;
begin
wk1:=CreateTask(TMyTask.Create(1,3000000)).OnMessage(Self);
wk2:=CreateTask(TMyTask.Create(2,4000000)).OnMessage(Self);
wk3:=CreateTask(TMyTask.Create(3,5000000)).OnMessage(Self);
end;
procedure TForm1.DoSometingAfterFinished;
begin
ShowMessage('Finished!');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
GlobalOmniThreadPool.MaxExecuting:=2*System.CPUCount;
GlobalOmniThreadPool.MaxQueued:=3;
waitGroup := CreateTaskGroup;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
waitGroup.TerminateAll;
end;
procedure TForm1.MsgNotify(var msg: TOmniMessage);
var
S : String;
begin
S:=msg.MsgData.AsArrayItem[1].AsString;
case msg.MsgData.AsArrayItem[0].AsInteger of
1 : Label1.Caption:=S;
2 : Label2.Caption:=S;
3 : Label3.Caption:=S;
end;
end;
end.
Thanks,
Davide