JRG*_*JRG 2 delphi multithreading task
我需要创建一些iTasks,它们将在不同的位置填充相同的数组.由于要为每个Task执行的代码是相同的,我决定创建一个iTasks数组并创建4个任务.将参数传递给iTask内的主要程序时出现问题.当我使用变量作为参数时,只考虑创建的最后一个任务的值.当我将参数作为值传递(硬编码)时,它会尊重每个任务的所有值.请看我的代码:
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
UNTThreads, Vcl.StdCtrls,
System.Threading ;
type
Vet = array of integer;
type
TFMThreadArray = class(TForm)
EDTArraySize: TEdit;
EDTNumberofThreads: TEdit;
Memo1: TMemo;
LBArraySize: TLabel;
LBThreads: TLabel;
BTUsingForLoop: TButton;
EDTThread: TEdit;
BTHardCoded: TButton;
procedure BTUsingForLoopClick(Sender: TObject);
procedure BTHardCodedClick(Sender: TObject);
private
{ Private declarations }
procedure ProcA ( Const pin, pfin, Psize, Ptask : integer;
Var Parray : vet);
public
{ Public declarations }
end;
var
FMThreadArray: TFMThreadArray;
implementation
{$R *.dfm}
// Procedure to be called by each iTask
procedure TFMThreadArray.ProcA ( Const pin, pfin, Psize, Ptask : integer;
Var Parray : vet);
var
vind : integer;
begin
for vind := pin to pfin do
begin
Parray[vind] := vind * 10;
end;
end;
Run Code Online (Sandbox Code Playgroud)
==>以下方法BTHardCodedClick产生预期结果.它相应地填充数组.但它在创建4个iTasks和在ProcA中传递参数时是硬编码的.我不想这样实现!
procedure TFMThreadArray.BTHardCodedClick(Sender: TObject);
var
varray : vet;
ind, indtask : Integer;
Ptasks : array of iTask;
begin
memo1.Clear;
SetLength(PTasks,Strtoint(EDTNumberofThreads.text));
SetLength(varray,StrToint(EDTarraysize.text));
// fill array with a initial value -2
for ind := Low(varray) to High(varray) do
varray[ind] :=-2;
// when call ProcA passing values parameters it works propperly
PTasks[0] := TTask.Create( procedure
begin
ProcA(0,3,16,0,varray) ;
end
) ;
PTasks[1] := TTask.Create( procedure
begin
ProcA(4,7,16,1,varray) ;
end
) ;
PTasks[2] := TTask.Create( procedure
begin
ProcA(8,11,16,2,varray) ;
end
) ;
PTasks[3] := TTask.Create( procedure
begin
ProcA(12,15,16,3,varray) ;
end
) ;
for Indtask := Low(Ptasks) to High(Ptasks) do
Ptasks[Indtask].Start;
TTask.WaitForAll(Ptasks);
memo1.Clear;
memo1.Lines.Add(' ============== Creating TASKs with hard-coded parameters ===============');
memo1.lines.add(' Array size : ' + EDTArraySize.text +
' number of Tasks : ' + EDTNumberofThreads.text);
memo1.Lines.Add(' =========================================================');
for ind := Low(varray) to High(varray) do
memo1.Lines.Add(' Array position : ' + Format('%.3d',[ind]) +
' content : ' + varray[ind].ToString );
end;
Run Code Online (Sandbox Code Playgroud)
===>以下方法是我想实现的方法但是它不起作用!因为它没有填充数组.似乎只有最后一个iTask"PTasks [indtask]"正在执行.
procedure TFMThreadArray.BTUsingForLoopClick(Sender: TObject);
var
varray : vet;
Ptasks : array of iTask;
vind, indtask, vslice : Integer;
vfirst, vlast, vthreads, vsize : Integer;
begin
vthreads := Strtoint(EDTNumberofThreads.text);
vsize := StrToint(EDTArraysize.text);
SetLength(PTasks,vthreads);
SetLength(varray,vsize);
for vind := Low(varray) to High(varray) do
varray[vind]:=-33;
vslice := Length(varray) div vthreads;
for indtask := Low(PTasks) to High(PTasks) do
begin
vfirst := indtask * vslice;
vlast := (indtask + 1) * vslice - 1;
if (Length(varray) mod vthreads <> 0) and (indtask = High(Ptasks)) then
vlast := HIgh(varray);
PTasks[indtask] := TTask.Create( procedure
begin
procA(vfirst,vlast,vsize,indtask,varray) ;
end
) ;
end;
// Starting all Tasks
for Indtask := Low(Ptasks) to High(Ptasks) do
Ptasks[Indtask].Start;
// Waits until all Tasks been concluded
TTask.WaitForAll(Ptasks);
memo1.Clear;
memo1.Lines.Add(' ============= Using For Loop to create the TASKs =====================');
memo1.lines.add(' Array size : ' + EDTArraySize.text +
' number of Tasks : ' + EDTNumberofThreads.text);
memo1.Lines.Add(' =========================================================');
for vind := Low(varray) to High(varray) do
memo1.Lines.Add(' Array position : ' + Format('%.3d',[vind]) +
' content : ' + varray[vind].ToString );
end;
end.
Run Code Online (Sandbox Code Playgroud)
我无法理解为什么在iTask中调用procA(vfirst,vlast,vsize,indtask,varray)不考虑参数vfirst,vlast的值.在此先感谢您的帮助 !
您观察到的效果是由于匿名方法变量捕获机制.它不会在代码执行期间捕获特定点的变量值,而是捕获变量的位置.
由于所有任务都在创建它们的循环之后运行,因此您将只看到存储的最后一个值.
要解决您的问题,您必须添加其他功能,以确保您不会捕获任务中的常见变量.
function CreateTask(vfirst, vlast, vsize, indtask: integer; var varray: Vet): ITask;
var
va: Vet;
begin
// var parameter cannot be captured so we have to store it into
// local variable - dynamic arrays act like pointers and any changes
// to local variable will actually change the original too
va := varray;
Result := TTask.Create(
procedure
begin
ProcA(vfirst, vlast, vsize, indtask, va);
end);
end;
Run Code Online (Sandbox Code Playgroud)
然后你称之为
Ptasks[indtask] := CreateTask(vfirst, vlast, vsize, indtask, varray);
Run Code Online (Sandbox Code Playgroud)
当然,如果符合您的需要,您也可以删除您的ProcA程序并将其逻辑直接合并到CreateTask函数中.