瞧代码:
unit unMain;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,
unThread;type
TfrmMain = class(TForm)
btn1: TButton;
btn2: TButton;
lbl1: TLabel;
lbl2: TLabel;
lbl3: TLabel;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
private
{ Private declarations }
myThread:TMyThread; public
{ Public declarations } end;var
frmMain: TfrmMain;
EndThread:Boolean;implementation{$R *.dfm}procedure TfrmMain.btn1Click(Sender: TObject);
begin
EndThread:=False;
myThread:=TMyThread.Create(False);end;procedure TfrmMain.btn2Click(Sender: TObject);
var
rv:DWORD;
wv:Integer;
i:Integer;
begin
rv:=5; myThread.Terminate; Application.ProcessMessages; //就是这里了,一定要加这句,下面的一句WaitForSingleObject()才有效,才不会超时! 如果不加,都是超时的(当然是线程还没有执行完,要Terminate中断的情况下)
rv:=WaitForSingleObject(myThread.Handle,5000);
case rv of
WAIT_ABANDONED: lbl3.Caption:='中断了';
WAIT_OBJECT_0: lbl3.Caption:='正常结束';
WAIT_TIMEOUT : lbl3.Caption:='超时';
5:lbl3.Caption:='55555';
end;end;end.
unit unThread;interfaceuses
Windows, Classes;type
TMyThread = class(TThread)
private
{ Private declarations }
procedure OnMyThreadTerminate(Sender:TObject);
protected
procedure Execute; override;
end;implementationuses unMain;{ TMyThread }procedure TMyThread.Execute;
var
i,j:Integer;
k:Double;
begin
OnTerminate:=OnMyThreadTerminate;
//FreeOnTerminate:=True; //这个设置了,就不能用WaitForSingleObject()函数了,因为句柄被释放了,我估计
for i:=0 to 2000000 do
begin
if Terminated then
Break;
for j:=0 to 2000 do
begin
if Terminated then
Break;
k:=(i+1) / Sqrt(Sqr((j+5)/5)+16);
end;
end;end;procedure TMyThread.OnMyThreadTerminate(Sender: TObject);
begin
frmMain.lbl1.Caption:='Thread Terminate';
end;end.如果不加Application.ProcessMessages;这句代码,也可以在别的地方设置myThread.Terminate;比如在另一个按钮点击事件里也行。有人能解释下这个事吗?有时想结束一个线程,设置了Terminate=true,不一定马上结束,所以想用WaitForSingleObject()来判断,线程运行时是无信号状态,结束了是有信号状态。也看了看<<windows核心编程>>相关章节,都是用API实现的。
unit unMain;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,
unThread;type
TfrmMain = class(TForm)
btn1: TButton;
btn2: TButton;
lbl1: TLabel;
lbl2: TLabel;
lbl3: TLabel;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
private
{ Private declarations }
myThread:TMyThread; public
{ Public declarations } end;var
frmMain: TfrmMain;
EndThread:Boolean;implementation{$R *.dfm}procedure TfrmMain.btn1Click(Sender: TObject);
begin
EndThread:=False;
myThread:=TMyThread.Create(False);end;procedure TfrmMain.btn2Click(Sender: TObject);
var
rv:DWORD;
wv:Integer;
i:Integer;
begin
rv:=5; myThread.Terminate; Application.ProcessMessages; //就是这里了,一定要加这句,下面的一句WaitForSingleObject()才有效,才不会超时! 如果不加,都是超时的(当然是线程还没有执行完,要Terminate中断的情况下)
rv:=WaitForSingleObject(myThread.Handle,5000);
case rv of
WAIT_ABANDONED: lbl3.Caption:='中断了';
WAIT_OBJECT_0: lbl3.Caption:='正常结束';
WAIT_TIMEOUT : lbl3.Caption:='超时';
5:lbl3.Caption:='55555';
end;end;end.
unit unThread;interfaceuses
Windows, Classes;type
TMyThread = class(TThread)
private
{ Private declarations }
procedure OnMyThreadTerminate(Sender:TObject);
protected
procedure Execute; override;
end;implementationuses unMain;{ TMyThread }procedure TMyThread.Execute;
var
i,j:Integer;
k:Double;
begin
OnTerminate:=OnMyThreadTerminate;
//FreeOnTerminate:=True; //这个设置了,就不能用WaitForSingleObject()函数了,因为句柄被释放了,我估计
for i:=0 to 2000000 do
begin
if Terminated then
Break;
for j:=0 to 2000 do
begin
if Terminated then
Break;
k:=(i+1) / Sqrt(Sqr((j+5)/5)+16);
end;
end;end;procedure TMyThread.OnMyThreadTerminate(Sender: TObject);
begin
frmMain.lbl1.Caption:='Thread Terminate';
end;end.如果不加Application.ProcessMessages;这句代码,也可以在别的地方设置myThread.Terminate;比如在另一个按钮点击事件里也行。有人能解释下这个事吗?有时想结束一个线程,设置了Terminate=true,不一定马上结束,所以想用WaitForSingleObject()来判断,线程运行时是无信号状态,结束了是有信号状态。也看了看<<windows核心编程>>相关章节,都是用API实现的。
procedure TMyThread.Execute;
begin
//执行任务
PostMessage(窗体的Handle,自己的消息,0,0);
end;窗体在收到消息后在进行其它的工作。如果你非要同步等待,那你可以先将 线程的 Handle 保存起来放在一个变量中,不要总是用MyThread.handle.
这样就算是是MyThread释放了也没有关系。在就是使用一个临界区,线程开始运行时进入,线程结束时关闭临界区。
在停止线程时先 调用 Terminate,然后下面的代码就是进入临界区,如果线程还没有结束,主线程就会等。最好用消息的方式,这样不会将让主线程假死。
我关心的是线程释放的时候,是要知道线程什么时候真正结束了,设置了Terminate,线程不一定就结束了,可能还在运行中。
因为某些原因,有些步骤要等线程结束了才能继续下去,所以用WaitForSingleObject来判断线程真正结束情况(当然可以有其它方法来判断,不过用WaitForSingleObject感觉比较直观).
呵呵,欢迎大家继续指教
置顶的帖子就可以了。
http://topic.csdn.net/u/20110217/11/56577c65-2e77-4f8f-b541-0be47cdb4d60.html?61869
if Terminated then
Break;
换成
if WaitForSingleObject(ExitEvent,0)=WAIT_OBJECT_0 then
break;线程类中添加
ExitEvent:TEvent; procedure Stop();
begin
QuitEvent.SetEvent;
end;
主线程调用:
myThread.Terminate;
换成
myThread.Stop;
我现在要关心的是我贴子里那句Application.ProcessMessages;
这句代码如果去掉了,就是超时的,我只是想知道为什么?
begin
WaitForSingleObject(theEvent,INFINITE);//theEvent是同步事件 //任务
end;
OnTerminate:=OnMyThreadTerminate;
OnTerminate帮助上的解释
Occurs after the thread's Execute method has returned and before the thread is destroyed。
OnTerminate去执行操作主线程上的控件去了
而ProcessMessages则是要求理解处理队列中的要求,如果没有ProcessMessages可能就会过一会才会处理界面上的控件。
PS:如果说的不对,坐等高手指点
呵呵
应当不是这个原因,OnTerminate事件是在主线程执行的,不是在本线程执行,所以不用放在Synchronize里执行了,还有不分配这个事件,情况也是如此
是这样的,但是如果我在主线程里发出了myThread.Terminate;命令,然后再waitforsingleobject(),这个等待时间是很少的(百微秒级的),倒是不用关心界面操作的问题了比如我这样写:
myThread.Terminate;
Sleep(2000);
WaitForSingleObject(myThread.Handle,10000);这个WaitForSingleObject还是报超时的
所以只能等到 WaitForSingleObject 超时结束线程才能执行完 OnTerminate .
Application.ProcessMessages 造成的不超时只是假象,Application.ProcessMessages执行后,主线程响应了你的frmMain.lbl1.Caption:='Thread Terminate';方法,将这行代码执行完成了,这时线程真正结束了,你看到没有超时。
你在你 procedure TMyThread.Execute;的代码最后加一个 windows.Beep(1000,300);就算你有Application.ProcessMessages肯定还是超时。因为在执行Application.ProcessMessages后线程又执行了100毫秒,这里系统又早将执行权利交给了线程,又阻塞了。没有 windows.Beep(1000,300);的时候,系统利用Application.ProcessMessages切换线程执行完成了OnTerminate 方法,然后才到了WaitForSingleObject 这句,所以看着好象没有超时。如果要用WaitForSingleObject 等,就不要执行OnTerminate方法。
最好是用PostMessage消息的方式。象OnTerminate 这种方法线程的源码是
procedure TThread.DoTerminate;
begin
if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);
end;
它会去主线程中执行,所以这时主线程决不能阻塞了,否则子线程肯定也阻塞了.
这个"OnTerminate在主线程里执行",误导我了
把这个OnTerminate去了就OK了。
begin
//
end;
//
end;
这种代码应该没有关系吧,编译器应该可以优化掉,你测试一下.