Delphi(D11) PPL中TTask匿名函数变量捕获异常问题咨询
Delphi PPL 任务输出重复值的原因与解决方法
这是并行编程里特别常见的变量捕获陷阱,你踩的这个坑本质是Delphi匿名函数对外部变量的捕获逻辑——它抓的是变量的引用,不是循环迭代那一刻的具体值。
咱们拆解下你的代码:循环里每次把j := i,然后创建的匿名函数引用了j。但循环跑起来的速度比任务执行快多了,等3秒后任务开始执行SendDebugFmt的时候,整个循环已经跑完,j的最终值是5,所以所有任务输出的都是最后一次的5。
解决这个问题有两种常用方案:
方案1:循环内创建局部变量绑定当前值
在循环内部声明一个局部变量,把当前迭代的i赋值给它,这样每次迭代都会生成一个独立的变量实例,匿名函数捕获的是这个专属的局部变量,就不会和其他任务共享引用了:
procedure TForm2.LaunchTasks; const cmax = 5; Var ltask: ITask; i: Integer; begin for i := 1 to cmax do begin // 每次迭代都会生成一个新的localJ实例 var localJ := i; ltask := TTask.Create( procedure () begin Sleep(3000); SendDebugFmt('Task #%d' ,[localJ]) end); ltask.Start; end; end;
方案2:用TTask.Run的参数传递值
Delphi 11支持TTask.Run的重载方法,你可以直接把当前迭代的i作为参数传递给任务,这样就彻底绕过了变量引用的问题:
procedure TForm2.LaunchTasks; const cmax = 5; Var i: Integer; begin for i := 1 to cmax do begin TTask.Run(procedure(const taskParam: Integer) begin Sleep(3000); SendDebugFmt('Task #%d' ,[taskParam]) end, i); end; end;
这两种方法的核心都是让每个任务绑定到当前迭代的具体数值,而不是共享同一个变量的引用,这样就能得到你预期的Task #1到Task #5的输出了。
内容的提问来源于stack exchange,提问作者user8934301
相关产品推荐
相关产品推荐

