瞧代码:
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实现的。

解决方案 »

  1.   

    最好用消息的方式,在
    procedure TMyThread.Execute;
    begin
      //执行任务
      PostMessage(窗体的Handle,自己的消息,0,0);
    end;窗体在收到消息后在进行其它的工作。如果你非要同步等待,那你可以先将 线程的 Handle 保存起来放在一个变量中,不要总是用MyThread.handle.
    这样就算是是MyThread释放了也没有关系。在就是使用一个临界区,线程开始运行时进入,线程结束时关闭临界区。
    在停止线程时先 调用 Terminate,然后下面的代码就是进入临界区,如果线程还没有结束,主线程就会等。最好用消息的方式,这样不会将让主线程假死。
      

  2.   

    To:ZyxIp谢谢你的回答,我关心的不是这个,你看我标识的红字。
    我关心的是线程释放的时候,是要知道线程什么时候真正结束了,设置了Terminate,线程不一定就结束了,可能还在运行中。
    因为某些原因,有些步骤要等线程结束了才能继续下去,所以用WaitForSingleObject来判断线程真正结束情况(当然可以有其它方法来判断,不过用WaitForSingleObject感觉比较直观).
    呵呵,欢迎大家继续指教
      

  3.   

    你这个情况看看
    置顶的帖子就可以了。
    http://topic.csdn.net/u/20110217/11/56577c65-2e77-4f8f-b541-0be47cdb4d60.html?61869
      

  4.   

    类似于这样的:
      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;
      

  5.   

    to:m617105置顶贴有吗?置顶贴关于线程运用的方式感觉好繁琐。我实际中用的线程还用不到贴子里说的那种方法。
    我现在要关心的是我贴子里那句Application.ProcessMessages;
    这句代码如果去掉了,就是超时的,我只是想知道为什么?
      

  6.   

    我实际中用的线程Execute()的代码大概是这样的:while not Terminate do
    begin
      WaitForSingleObject(theEvent,INFINITE);//theEvent是同步事件  //任务
    end;
      

  7.   

    个人估计可能跟下面这句有关系
    OnTerminate:=OnMyThreadTerminate;
    OnTerminate帮助上的解释
    Occurs after the thread's Execute method has returned and before the thread is destroyed。
    OnTerminate去执行操作主线程上的控件去了
    而ProcessMessages则是要求理解处理队列中的要求,如果没有ProcessMessages可能就会过一会才会处理界面上的控件。
    PS:如果说的不对,坐等高手指点
      

  8.   


    呵呵
    应当不是这个原因,OnTerminate事件是在主线程执行的,不是在本线程执行,所以不用放在Synchronize里执行了,还有不分配这个事件,情况也是如此
      

  9.   

    其次少说了一点waitforsingleobject会让主线程直接进入休息状态,也就不会处理你操作界面控件
      

  10.   


    是这样的,但是如果我在主线程里发出了myThread.Terminate;命令,然后再waitforsingleobject(),这个等待时间是很少的(百微秒级的),倒是不用关心界面操作的问题了比如我这样写:
    myThread.Terminate;
    Sleep(2000);
    WaitForSingleObject(myThread.Handle,10000);这个WaitForSingleObject还是报超时的
      

  11.   

    线程的 OnTerminate 是要和主线程进行同步的。而这时主线程因为 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方法。
      

  12.   

    粗步想法,是不是和消息队列和循环机制有关啊,因为是插入Application.ProcessMessages;这个是最顶层的消息处理环节了
      

  13.   

    线程使用的基本原则就是不要在线程中去操作主线程的界面控件,这些控件都不是线程安全的.
    最好是用PostMessage消息的方式。象OnTerminate 这种方法线程的源码是
    procedure TThread.DoTerminate;
    begin
      if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);
    end;
    它会去主线程中执行,所以这时主线程决不能阻塞了,否则子线程肯定也阻塞了.
      

  14.   

    2位大侠,就是你们说的情况了!!!
    这个"OnTerminate在主线程里执行",误导我了
    把这个OnTerminate去了就OK了。
      

  15.   

    杯具的是,我在线程单元里留下这样的代码:procedure TMyThread.OnMyThreadTerminate(Sender: TObject);
    begin
      //
    end;
      

  16.   

    begin
      //
    end;
    这种代码应该没有关系吧,编译器应该可以优化掉,你测试一下.