很多时候我们会用ttask.waitforall等待一组任务的结果,然后在主线程UI里面报告运行结果, 因为waitforall方法是阻塞式的等待,如果直接在主线程里执行,会卡死UI, 所以就尝试开另一个task用来等待这组任务的结束,如下代码:
var
aTask: array of ITask;
i: integer;
begin
sfLogger.logMessage('The start.');
setlength(aTask, 10);
for i := 0 to 9 do
begin
aTask[i] := TTask.Run(
procedure
var
aValue: integer;
begin
aValue := Random(2000);
sleep(aValue);
tthread.Synchronize(nil,
procedure
begin
mmo1.Lines.Add(aValue.ToString());
end);
end);
end;
TTask.Run(
procedure
begin
TTask.WaitForAll(aTask);
tthread.Synchronize(nil,
procedure
begin
mmo1.Lines.Add('END.');
end);
end);
end;
运行是很顺利, 但当关闭应用后报告有内存出错!
很明显是这组TTask资源在运行过waitforall后就没能成功释放! 但如果在主线程里面用waitforall,则完全没这个问题!
所以建议自行用计算数记录剩余任务数的方法来自行处理等待吧!
下面是示例:
var
aTask: array of ITask;
i, lvC: integer;
begin
sfLogger.logMessage('The start.');
setlength(aTask, 10);
lvC := 0;
for i := 0 to 9 do
begin
AtomicIncrement(lvC);
aTask[i] := TTask.Run(
procedure
var
aValue: integer;
begin
aValue := Random(2000);
sleep(aValue);
tthread.Synchronize(nil,
procedure
begin
mmo1.Lines.Add(aValue.ToString());
end);
AtomicDecrement(lvC);
end);
end;
while lvC>0 do
Application.ProcessMessages;
mmo1.Lines.Add('END.');
{TTask.Run(
procedure
begin
TTask.WaitForAll(aTask);
tthread.Synchronize(nil,
procedure
begin
mmo1.Lines.Add('END.');
end);
end);}
end;
=======================
而具戏剧性的是,如果, 这个waitforall也不是一定不能放在task里面等待, 如果将aTask[i]:=TTask.run(...)这个变成通过一个procedure来赋值就没事:
procedure runtask(var aTask: ITask);
begin
aTask := TTask.Run(
procedure
var
aValue: integer;
begin
aValue := Random(2000);
sleep(aValue);
sfLogger.logMessage(aValue.ToString());
end);
end;
procedure TForm1.Button4Click(Sender: TObject);
var
aTask: array of ITask;
i: integer;
begin
sfLogger.logMessage('The start.');
setlength(aTask, 10);
for i := 0 to 9 do
begin
// Sleep(1);
runtask(aTask[i]);
end;
TTask.Run(
procedure
begin
TTask.WaitForAll(aTask);
tthread.Synchronize(nil,
procedure
begin
mmo1.Lines.Add('END.');
end);
end);
end;
而runtask可以是procedure也可以是function, 但一定不能是嵌套函数,否则也会内存泄露.
这算不算XE7的大坑??!!不知道10.2有没有修复此问题.