使用WaitForMultipleObject等待多个线程 [英] Waiting for multiples threads using WaitForMultipleObjects

查看:240
本文介绍了使用WaitForMultipleObject等待多个线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆