慎用DelphiXE的TTask.WaitForAll/WaitForAny 一不小心會造成記憶體洩露!
阿新 • • 發佈:2019-02-06
很多時候我們會用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有沒有修復此問題.