使用WaitForMultipleObject等待多个线程 [英] Waiting for multiples threads using WaitForMultipleObjects
问题描述
我正在使用 WaitForMultipleObjects
函数来等待几个线程的完成,但是我做错了,因为结果不是预期的
查看此示例代码
键入
TForm1 = class(TForm)
Memo1:TMemo;
Button1:TButton;
procedure Button1Click(Sender:TObject);
private
end;
TFoo = class(TThread)
private
因子:Double;
procedure ShowData;
protected
procedure Execute;覆盖
构造函数Create(AFactor:Double);
结束
var
Form1:TForm1;
实现
使用
数学;
{$ R * .dfm}
{TFoo}
构造函数TFoo.Create(AFactor:Double);
begin
继承Create(False);因子:= AFactor;
FreeOnTerminate:= True;
end;
程序TFoo.Execute;
const
Max = 100000000;
var
i:整数;
开始
继承;
for i:= 1 to Max do
因子:= Sqrt(Factor);
同步(ShowData);
结束
程序TFoo.ShowData;
begin
Form1.Memo1.Lines.Add(FloatToStr(Factor));
结束
procedure TForm1.Button1Click(Sender:TObject);
const
nThreads = 5;
Var
tArr:数组[1..nThreads]的TFoo;
hArr:数组[1..nThreads]的THandle;
i:整数;
rWait:红衣主教;
begin
for i:= 1 to nThreads do
begin
tArr [i]:= TFoo.Create(Pi * i);
hArr [i]:= tArr [i] .Handle;
结束
重复
rWait:= WaitForMultipleObjects(nThreads,@hArr,True,100);
Application.ProcessMessages;
,直到rWait WAIT_TIMEOUT;
//这里我想在所有线程终止时显示此消息
Memo1.Lines.Add('Wait done');
结束
结束。
这是演示应用程序的当前输出
1
等待完成
1
1
1
1
但我想要这样的东西
1
1
1
1
1
等待完成
如何使用 WaitForMultipleObjects
函数等待所有线程终止?
修复:删除FreeOnTerminate。
当您仍然需要手柄时,您的代码会导致线程被释放。这是一个大错误,您可以在代码中的其他位置获取访问冲突,或者从WaitFormMultipleObjects返回的错误返回代码。
当TThread时,TThread.handle无效被释放,并且由于句柄不再有效,因此提前终止您的等待循环。您还可能会遇到访问访问冲突,如果您在后台被释放后尝试访问TThread,那么我认为最好是在已知时间内释放它们。
使用线程句柄作为事件句柄工作正常,但是不要使用FreeOnTerminate在线程终止时释放线程,因为这会很快破坏句柄。
我也同意那些说使用Application.Processmessages做一个忙碌的等待循环的人很丑陋。还有其他方法可以做到这一点。
unit threadUnit2;
接口
使用Classes,SyncObjs,Windows,SysUtils;
type
TFoo = class(TThread)
private
FFactor:Double;
procedure ShowData;
protected
procedure Execute;覆盖
构造函数Create(AFactor:Double);
析构函数覆盖
结束
程序WaitForThreads;
实现
使用
表单,
数学;
程序跟踪(msg:String);
begin
如果分配(Form1)然后
Form1.Memo1.Lines.Add(msg);
结束
{TFoo}
构造函数TFoo.Create(AFactor:Double);
begin
继承Create(False);
FFactor:= AFactor;
// FreeOnTerminate:= True;
end;
析构函数TFoo.Destroy;
开始
继承;
结束
程序TFoo.Execute;
const
Max = 100000000;
var
i:整数;
开始
继承;
for i:= 1 to Max do
FFactor:= Sqrt(FFactor);
同步(ShowData);
结束
程序TFoo.ShowData;
begin
Trace(FloatToStr(FFactor));
结束
程序WaitForThreads;
const
nThreads = 5;
Var
tArr:数组[1..nThreads]的TFoo;
hArr:数组[1..nThreads]的THandle;
i:整数;
rWait:红衣主教;
begin
for i:= 1 to nThreads do
begin
tArr [i]:= TFoo.Create(Pi * i);
hArr [i]:= tArr [i] .handle; // Event.Handle;
结束
重复
rWait:= WaitForMultipleObjects(nThreads,@hArr [1],{waitAll} True,150);
Application.ProcessMessages;
,直到rWait WAIT_TIMEOUT;
睡眠(0);
//这里我想在所有线程终止时显示此消息
Trace('Wait done');
for i:= 1 to nThreads do
begin
tArr [i] .Free;
结束
end;
结束。
I'm using the WaitForMultipleObjects
function to wait for the finalization of several threads, but I'm doing something wrong because the result is not the expected
see this sample code
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
end;
TFoo = class(TThread)
private
Factor: Double;
procedure ShowData;
protected
procedure Execute; override;
constructor Create(AFactor : Double);
end;
var
Form1: TForm1;
implementation
Uses
Math;
{$R *.dfm}
{ TFoo }
constructor TFoo.Create(AFactor: Double);
begin
inherited Create(False);
Factor := AFactor;
FreeOnTerminate := True;
end;
procedure TFoo.Execute;
const
Max=100000000;
var
i : Integer;
begin
inherited;
for i:=1 to Max do
Factor:=Sqrt(Factor);
Synchronize(ShowData);
end;
procedure TFoo.ShowData;
begin
Form1.Memo1.Lines.Add(FloatToStr(Factor));
end;
procedure TForm1.Button1Click(Sender: TObject);
const
nThreads=5;
Var
tArr : Array[1..nThreads] of TFoo;
hArr : Array[1..nThreads] of THandle;
i : Integer;
rWait : Cardinal;
begin
for i:=1 to nThreads do
begin
tArr[i]:=TFoo.Create(Pi*i);
hArr[i]:=tArr[i].Handle;
end;
repeat
rWait:= WaitForMultipleObjects(nThreads, @hArr, True, 100);
Application.ProcessMessages;
until rWait<>WAIT_TIMEOUT;
//here I want to show this message when all the threads are terminated
Memo1.Lines.Add('Wait done');
end;
end.
this is the current output of the demo app
1
Wait done
1
1
1
1
but I want something like this
1
1
1
1
1
Wait done
How I must use the WaitForMultipleObjects
function to wait until all the thread are terminated?
Fix: Remove the FreeOnTerminate.
Your code causes the threads to be freed, when you still need the handles. That's a big bug, and you can get access violations somewhere else in your code, or error return codes coming back from your WaitFormMultipleObjects.
TThread.handle becomes invalid when the TThread is freed, and this terminates your wait loop early because the handle is no longer valid. You could also experience an access access violation, if you tried to access the TThread after it was freed in the background, so I believe it's better to free them intentionally, and at a known time.
Using the thread handle as an event handle works fine, but you should not use FreeOnTerminate to free the thread when it terminates it as this destroys the handles too soon.
I also agree with the people who said that doing a busy-waiting loop with Application.Processmessages is pretty ugly. There are other ways to do that.
unit threadUnit2;
interface
uses Classes, SyncObjs,Windows, SysUtils;
type
TFoo = class(TThread)
private
FFactor: Double;
procedure ShowData;
protected
procedure Execute; override;
constructor Create(AFactor : Double);
destructor Destroy; override;
end;
procedure WaitForThreads;
implementation
Uses
Forms,
Math;
procedure Trace(msg:String);
begin
if Assigned(Form1) then
Form1.Memo1.Lines.Add(msg);
end;
{ TFoo }
constructor TFoo.Create(AFactor: Double);
begin
inherited Create(False);
FFactor := AFactor;
// FreeOnTerminate := True;
end;
destructor TFoo.Destroy;
begin
inherited;
end;
procedure TFoo.Execute;
const
Max=100000000;
var
i : Integer;
begin
inherited;
for i:=1 to Max do
FFactor:=Sqrt(FFactor);
Synchronize(ShowData);
end;
procedure TFoo.ShowData;
begin
Trace(FloatToStr(FFactor));
end;
procedure WaitForThreads;
const
nThreads=5;
Var
tArr : Array[1..nThreads] of TFoo;
hArr : Array[1..nThreads] of THandle;
i : Integer;
rWait : Cardinal;
begin
for i:=1 to nThreads do
begin
tArr[i]:=TFoo.Create(Pi*i);
hArr[i]:=tArr[i].handle; // Event.Handle;
end;
repeat
rWait:= WaitForMultipleObjects(nThreads, @hArr[1],{waitAll} True, 150);
Application.ProcessMessages;
until rWait<>WAIT_TIMEOUT;
Sleep(0);
//here I want to show this message when all the threads are terminated
Trace('Wait done');
for i:=1 to nThreads do
begin
tArr[i].Free;
end;
end;
end.
这篇关于使用WaitForMultipleObject等待多个线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!