I have the following code. It creates 3 tasks and then calls `TTask.WaitForAll(tasks)` :
procedure TVideoFrame.AddVideo(....);
var
...
begin
MainTrace.SendStack('AddVideo');
btnPaste.Enabled := False;
btnUpdate.Enabled := False;
Application.ProcessMessages;
...
TTask.Run(procedure()
var
tasks: array of ITask;
...
S: String;
Res: Integer;
begin
Setlength(tasks ,3);
MemStream := nil;
tasks[0] := TTask.Create (procedure ()
begin
...
end);
tasks[0].Start;
tasks[1] := TTask.Create (procedure ()
begin
MainTrace.Send('Run Task 1');
S := GetHtml(Url);
end);
tasks[1].Start;
tasks[2] := TTask.Create (procedure ()
begin
...
end);
tasks[2].Start;
MainTrace.Send('WaitForAll');
TTask.WaitForAll(tasks);
EnterCriticalSection(_CritSec); // Don't think it's necessary but just to be safe...
try
try
.... // Process results..
except
On E: Exception do
MainTrace.Send(E.ClassName, E.Message);
end;
finally
LeaveCriticalSection(_CritSec);
end;
TThread.Synchronize(nil, procedure()
begin
btnUpdate.Enabled := True;
btnPaste.Enabled := True;
....
end);
end);
end;
A normal trace would look like this:
It seems a little strange that the trace of `WaitForAll` happens before `Run Task 1`, but maybe that's because it takes a few moments before Task 1 starts to run. Anyway that is not the main issue.
The problem is I get a trace like this:
Task 1 is running twice, and you can see from the trace in a different thread. I also have a breakpoint in the `GetHtml` method, and I see that in fact it is being called twice. How does this happen? In the main user interface I only click the button once. (as you can see from the code, I disable the button so I can't click it twice anyway..)
Thanks
Rael
try my sample
UI main totally responsive!
unit uFormMain;
interface
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
Vcl.StdCtrls;
type
TForm1 = class(TForm)
btn_Start_TaskRUN: TButton;
Edit1: TEdit;
Edit2: TEdit;
btn_Stop_TaskRUN: TButton;
Memo1: TMemo;
procedure btn_Start_TaskRUNClick(Sender: TObject);
procedure btn_Stop_TaskRUNClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
System.Threading;
// Proc: TProc
var
lMyProc1: TProc = nil;
lMyProc2: TProc = nil;
lMyProc3: TProc = nil;
//
lMyValue1: integer = 0;
lMyValue2: integer = 0;
lMyValue3: integer = 0;
//
lMyTaskRUN_obj: ITask = nil;
//
lMyTasks: array [0 .. 2] of ITask = (
nil,
nil,
nil
); // if is only 3, then...
procedure prcTask1;
begin
// some code pertinent...
Sleep(3000);
lMyValue1 := 111;
end;
procedure prcTask2;
begin
// some code pertinent...
Sleep(2000);
lMyValue2 := 222;
end;
procedure prcTask3;
begin
// some code pertinent...
Sleep(5000);
lMyValue3 := 333;
end;
procedure TForm1.btn_Start_TaskRUNClick(Sender: TObject);
begin
lMyProc1 := prcTask1;
lMyProc2 := prcTask2;
lMyProc3 := prcTask3;
//
lMyTaskRUN_obj := TTask.Run( { }
procedure() { }
begin
//
lMyTasks[0] := TTask.Create(lMyProc1);
lMyTasks[1] := TTask.Create(lMyProc2);
lMyTasks[2] := TTask.Create(lMyProc3);
//
lMyTasks[0].Start;
lMyTasks[1].Start;
lMyTasks[2].Start;
//
Edit1.Text := 'Tasks started in: ' + TimeToStr(now);
//
TTask.WaitForAll(lMyTasks); { boolean return } // wait all task end = 3sec, 2sec and 5sec = 5sec is your time to wait!
// TTask.WaitForAny(lMyTasks); { integer return = task ID } // who's end firstly, then, go back! in this case, 2sec < 3sec < 5sec
//
Edit2.Text := 'Tasks ended in: ' + TimeToStr(now);
//
(*
try
TThread.Synchronize(nil,
procedure() { }
begin { }
TTask.WaitForAll(lMyTasks) { }
end { }
);
finally
end;
*)
//
ShowMessage('All done' + { }
sLineBreak + lMyValue1.ToString + { }
sLineBreak + lMyValue2.ToString + { }
sLineBreak + lMyValue3.ToString { }
);
end { }
); // TTask.Run... procedure...
//
end;
procedure TForm1.btn_Stop_TaskRUNClick(Sender: TObject);
var
i : integer;
lMyTaskWainting: ITask;
begin
try
if not(lMyTaskRUN_obj = nil) then
begin
Caption := 'not(lMyTaskRUN_obj = nil)';
//
// TTaskStatus = (Created, WaitingToRun, Running, Completed, WaitingForChildren, Canceled, Exception);
if (lMyTaskRUN_obj.Status = TTaskStatus.Running) then
begin
for lMyTaskWainting in lMyTasks do
if (lMyTaskWainting.Status in [TTaskStatus.Running, TTaskStatus.WaitingToRun]) then
lMyTaskWainting.Cancel;
//
lMyTaskRUN_obj.Cancel;
end;
//
Self.Close; // close app
end
else
Caption := 'lMyTaskRUN_obj = nil';
except
on E: Exception do
ShowMessage(E.Message);
end;
end;
initialization
ReportMemoryLeaksOnShutdown := true;
finalization
end.
hug