Delphi XE TTask.WaitForAll/WaitForAny 一不小心会造成内存泄露


本文整理自网络,侵删。

 
很多时候我们会用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有没有修复此问题.
――――――――――――――――

原文链接:https://blog.csdn.net/rocklee/article/details/72953953

相关阅读 >>

Delphi 设置系统静音取消系统静音

Delphi实现双击左ctrl键调用记事本

Delphi 取得某一天所在的星期一及星期天

Delphi 两个非常有用的进程函数

Delphi winapi: windowfrompoint- 获取指定点所在窗口的句柄

Delphi木马生成技术

Delphi rest客户端程序

Delphi屏蔽win、ctrl_esc、alt_tab、alt_f4等键(windows xp、windows 2003 server下测试通过)

Delphi firedac 连接access mdb数据库的方法

Delphi 试试带参数的 exit

更多相关阅读请进入《Delphi》频道 >>



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...