我的代码正在运行for循环来处理一些数据,如下所示
procedure printValue(Value: Integer);
begin
TThread.Synchronize(TThread.Current, procedure
begin
form1.memo1.lines.add( Value.ToString );
end);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
myThread : TThread;
Proc1: TMyProc;
begin
for I := 0 to 10 do
begin
myThread := TThread.CreateAnonymousThread(
procedure
begin
printValue( i );
end);
myThread.Start;
end;
end;
Run Code Online (Sandbox Code Playgroud)
输出的代码是这样的:
3
5
6
8
9
11
10
4
11
4
7
Run Code Online (Sandbox Code Playgroud)
这不好,所以我sleep(1)在线程启动后添加了一个小的延迟。这将解决输出问题,但不是一个好主意,因为在大循环中会阻塞ui线程,因此请尝试使用此文档作为帮助,这样我的代码就会这样更改:
function CaptureValue(Value: Integer): TMyProc;
begin
Result := procedure begin Writeln(Value); end;
end;
procedure printValue(Value: Integer);
begin
TThread.Synchronize(TThread.Current, procedure
begin
form1.memo1.lines.add( Value.ToString );
end);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
myThread : TThread;
Proc1: TMyProc;
begin
for I := 0 to 10 do
begin
myThread := TThread.CreateAnonymousThread(
procedure
begin
Proc1:= CaptureValue(i);
printValue( Proc1 );
end);
myThread.Start;
end;
end;
Run Code Online (Sandbox Code Playgroud)
但我有[dcc32 Error] Unit11.pas(57): E2010 Incompatible types: 'Integer' and 'procedure, untyped pointer or untyped parameter'错误。
我的代码有什么问题?
匿名过程捕获变量,而不是值。这是记录的行为。因此,在您的两个示例中,您的线程都共享一个I变量,并且对该变量的访问没有同步。
您有正确的想法传递I给过程,然后在使用它之前从参数列表中捕获它。但是,您以错误的方式进行操作。
您的第二个示例实际上无法编译的原因是因为您滥用了CaptureValue()。它返回一个TMyProc显然是a的reference to procedure(对于BTW,RTL TProc为此目的已经具有一个)。您正在按原样将匿名过程传递给printValue(),而需要一个Integer。那就是编译器错误所抱怨的。
您使用返回值的CaptureValue()方式必须改为返回一个本身返回一个匿名函数Integer(即,CaptureValue()返回return reference to function: Integer,即aka TFunc<Integer>)的匿名函数,然后调用该函数并将该返回值传递给PrintValue()。
但是,I在传递给它之前,您仍在捕获自身CaptureValue(),因此您仍具有线程共享I。您需要在调用CaptureValue()之前直接从循环内部进行调用CreateAnonymousThread()。但是然后,您的线程将Proc1改为捕获和共享变量,因此您将回到原来的问题。
话虽如此,请尝试以下类似的方法:
procedure PrintValue(Value: Integer);
begin
TThread.Synchronize(nil,
procedure
begin
Form1.Memo1.Lines.Add( Value.ToString );
end
);
end;
function CaptureAndPrintValue(Value: Integer): TProc;
begin
Result := procedure
begin
printValue( Value );
end
);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
begin
for I := 0 to 10 do
begin
TThread.CreateAnonymousThread(
CaptureAndPrintValue(I)
).Start;
end;
end;
Run Code Online (Sandbox Code Playgroud)
或者,您可以让RTL为您处理线程:
uses
..., System.Threading;
procedure PrintValue(Value: Integer);
begin
// can't use TThread.Synchronize() with TParallel, as it
// doesn't service the main message queue while looping...
TThread.Queue(nil,
procedure
begin
Form1.Memo1.Lines.Add( Value.ToString );
end
);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
TParallel.For(0, 10,
procedure(I: Integer)
begin
PrintValue(I);
end
);
end;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
194 次 |
| 最近记录: |