注意,没有线程的对象实例(TThread),只有ID或Handle另问也是如果只有ID或Handle,是否可以判断这是应用程序的主线程还是子线程呢?分不够另开贴加分,谢谢。

解决方案 »

  1.   

    搜索过以前的帖子,说GetExitThreadCode有问题,自己试过也确实这样不知道是否有其它好方法 -_-
      

  2.   

    很简单If (WaitForSingleObject(TTestThread.Handle,100) <> WAIT_TIMEOUT) then
    begin
      //TTestThread 不存在
    end 
    else
    begin
      //TTestThread 存在
    end;
      

  3.   

    至于是否主线程,我没办法从TThread.Handle上解决我的思路是,获得进程列表,从进程列表里面得到所有的主线程列表,对比得出是否主线程
      

  4.   

    除了WaitForSingleObject是否有不堵塞的方法呢?由于判断线程ID这部分的代码本身已经是设置了线程互斥的,如果要用WAITFORSINGLEOBJECT,就得重新设计把这部分代码搬进线程了,有点麻烦。
      

  5.   

    试过了,WaitForSingleObject不行的,第二次还是显示OK
    procedure TForm1.RzButton1Click(Sender: TObject);
    var
      a: TMyThread;
    begin
      a := TMyThread.Create(False);
      if WaitForSingleObject(a.Handle, 5000) = WAIT_TIMEOUT then
        ShowMessage('time out')
      else
        ShowMessage('ok');
      a.Free;
      if WaitForSingleObject(a.Handle, 5000) = WAIT_TIMEOUT then
        ShowMessage('time out')
      else
        ShowMessage('ok');
    end;
      

  6.   

      if GetCurrentThreadID = MainThreadID then
       showmessage('MainThread')  ;
      

  7.   

    orz.. 学到这个全局变量了,解决了第二个问题
      

  8.   


    你这样写是错的.
    第一:
        WaitForSingleObjectt(a.Handle,5000) //不要把时间设置成这么大,一般100就足够了,主线程阻塞太久很可能出现不可预知的错误第二:
       a.Free; 不应该这样结束线程,一旦线程处于阻塞状态,整个主线程都会卡死第三:
       线程里面应该时刻检查是否Terminated,否则,是释放不了的.
    例如
    线程里:procedure TMyThread.Execute;
    var
      i:Integer ;
    begin
      while not Terminated do
      begin
        inc(i,1);
        OutputDebugString(PChar(inttostr(i)));
        Sleep(100);
      end;
    end;
    假如改为procedure TMyThread.Execute;
    var
      i:Integer ;
    begin
      while true do
      begin
        inc(i,1);
        OutputDebugString(PChar(inttostr(i)));
        Sleep(100);
      end;
    end;这是释放不了的写程序,最好用标准的方法去写,上面的例子在2000/XP下线程有可能可以结束,但是在Vista下线程是不可能会结束的
      

  9.   

    再补充一下a := TMyThread.Create(false); 
    最好改为
    a := TMyThread.Create(True);
    a.Resume;线程创建还是需要有一定时间的,假如客户机器不好或者系统资源紧张,
    立刻用WaitForSingleObject去检测可能会出问题.(Handle不存在或者,刚好一个别的线程结束了这个新建立的线程的Handle和刚结束的线程Handle相同,而得到错误的结果)结束线程应该用 
    a.Terminate;
    a.free;
    a:=nil;这样才是完全的清理了a如果对线程的操作需要非常精细,建议你建立一个监视线程去对其他线程进行检测,检测结果通过消息或者事件进行处理和控制.线程不是那么简单的东西,Delphi的封装有比较大的局限性.还是多用API吧
      

  10.   

    如果没有CloseHandle是不会被重新分配的,即使是被重新分配,windows也会有一段时间间隔保证。Handle至少是32bit,而系统当中允许同时存在的Handle是相当有限的,所以几乎可以认为不可能被重分配,至少就目前的软硬件配置是安全的。
      

  11.   

    使用WaitFor是对的,但是关键要注意如果需要使用WaitFor的话,TThread的FreeOnTerminate属性不能设置为True,而需要手动去Free.
      

  12.   

    你说的我明白,但这不是我提问的问题的重点。1、wait 5000都不行,wait 100就可以了?
    2、我例子中的线程没挂起
    2、不知道你是否明白Execute和Terminated的关系,Execute函数是ThreadProc的主体,在如果我不检查Terminated,线程只是把里面的代码执行一次就进入等待结束状态而已,和线程是否能释放完全没关系。要时刻检查Terminated是因为TThread.Terminate(包括Free的时候调用的Terminate)只是在线程里设置了Terminated这个标记,如果不检查,线程就会停死在那个While循环,出不了Execute这个过程里而已。相信下面代码可以解答你的疑问:function ThreadProc(Thread: TThread): Integer;
    var
      FreeThread: Boolean;
    begin
    {$IFDEF LINUX}
      if Thread.FSuspended then sem_wait(Thread.FCreateSuspendedSem);
    {$ENDIF}
      try
        if not Thread.Terminated then
        try
          Thread.Execute;  <- 看这里
        except
          Thread.FFatalException := AcquireExceptionObject;
        end;
      finally
        FreeThread := Thread.FFreeOnTerminate;
        Result := Thread.FReturnValue;
        Thread.DoTerminate;
        Thread.FFinished := True;
        SignalSyncEvent;
        if FreeThread then Thread.Free;
    {$IFDEF MSWINDOWS}
        EndThread(Result);
    {$ENDIF}
    {$IFDEF LINUX}
        // Directly call pthread_exit since EndThread will detach the thread causing
        // the pthread_join in TThread.WaitFor to fail.  Also, make sure the EndThreadProc
        // is called just like EndThread would do. EndThreadProc should not return
        // and call pthread_exit itself.
        if Assigned(EndThreadProc) then
          EndThreadProc(Result);
        pthread_exit(Pointer(Result));
    {$ENDIF}
      end;
    end;
    constructor TThread.Create(CreateSuspended: Boolean);
    {$IFDEF LINUX}
    var
      ErrCode: Integer;
    {$ENDIF}
    begin
      inherited Create;
      AddThread;
      FSuspended := CreateSuspended;
      FCreateSuspended := CreateSuspended;
    {$IFDEF MSWINDOWS}
      FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);  <- 看这里
      if FHandle = 0 then
        raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(GetLastError)]);
    {$ENDIF}
    {$IFDEF LINUX}
      sem_init(FCreateSuspendedSem, False, 0);
      ErrCode := BeginThread(nil, @ThreadProc, Pointer(Self), FThreadID);
      if ErrCode <> 0 then
        raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(ErrCode)]);
    {$ENDIF}
    end;
      

  13.   

    上文中的“在如果我不检查Terminated”改为“如果我没加上while not terminated do”另外TThread.Destroy中是有CloseHandle的。destructor TThread.Destroy;
    begin
      if (FThreadID <> 0) and not FFinished then
      begin
        Terminate;
        if FCreateSuspended then
          Resume;
        WaitFor;
      end;
    {$IFDEF MSWINDOWS}
      if FHandle <> 0 then CloseHandle(FHandle);  <- 看这里
    {$ENDIF}
    {$IFDEF LINUX}
      // This final check is to ensure that even if the thread was never waited on
      // its resources will be freed.
      if FThreadID <> 0 then pthread_detach(FThreadID);
      sem_destroy(FCreateSuspendedSem);
    {$ENDIF}
      inherited Destroy;
      FFatalException.Free;
      RemoveThread;
    end;
      

  14.   

    Free里面有调用Terminate的,请去看VCL的代码。你的代码我用一行FreeAndNil(a)即可完成。
      

  15.   

    其实只要保证不检查被释放(CloseHandle)的线程,那么GetExitThreadCode是完全能够达到目的的。只要设计逻辑上能够达到这一点要求,就没问题了。
      

  16.   

    如果是觉得TThread当中的那个handle无法控制,那就通过DuplicateHandle或者OpenThread复制一个新的线程句柄(Handle)。
      

  17.   

    请问“保证不检查被释放(CloseHandle)的线程”是指?我只有一个Handle或者ID哦。
      

  18.   


    确实FreeAndNil(a)等价于a.free; a:=nil; 只是为了展示清楚写成这样,见笑了至于为什么
    我也说过了,主线程阻塞,可能会出现不可知的情况.
    至少在我测试的时候,在Vista/XP/2000下我的代码能够正常判断和工作我不知道对于"挂起"这个词我们的理解是否一致,我的理解线程处于Suspended状态下才能称为挂起
    我的代码中让Execute过程处于死循环状态,在我看来这不是挂起,只是死循环而已.
    在Execute过程中,线程外部调用Terminate,并不一定能有效终止线程.这是我的理解
    这个我不太懂,请指教...
      

  19.   

    我回去再试试wait 100,奇怪了,问题是我的主线程显然没有堵塞。
      

  20.   

    学习了~我估计总是要对线程句柄进行XX操作,
    然后看返回值或者GetLastError看看是不是有问题
      

  21.   

    使用GetExitCodeThread 就行了吧如果线程还在运行返回的貌似是STILL_ACTIVE 之类的
      

  22.   

    试过了,waitforsingleobject 100一样的,free之前和free之后得到的结果都一样.. 继续征解ing
      

  23.   

    这个并不能判断是否free,只能判断线程/进程的生命周期是否结束。
      

  24.   

    要把线程(操作系统调度CPU时钟的一个基本单位)和Delphi当中用于管理线程的TThread类的对象分开,两者概念上是不一样的。
      

  25.   

    我知道TThread是对系统进程的封装,但是我之前不是也列过VCL代码了么,TThread释放的时候有释放真正的线程的。
      

  26.   

    ps. 我现在要判断的是真正的线程是否存在,不是判断TTHREAD是否FREE
      

  27.   

    这个我应该在前面有提到过,那个释放只是释放对线程相关资源(句柄)的引用。所能管到的只是线程相关资源的某一计数的生命周期,可以在这个计数释放之前通过DuplicateHandle或者OpenThread来增加资源的引用计数来延长资源的生命周期,更需要注意的是,这只是操作系统为线程开辟并维护的相关上下文环境资源。而线程的生命周期并不依赖于外部对其资源的生命周期的管理。实际上操作系统会为线程维护一个相关资源的引用计数而保证线程的正常执行。线程的生命周期依赖于线程执行代码段的完成或终断与否。对于TThread来说,线程的生命周期由Execute及被其调用的过程/函数来维护。GetExitCodeThread只对线程的生命周期感兴趣,但是前提是它需要线程相关的资源(ThreadHandle)才可以访问到线程的状态。
      

  28.   

    哦,原来也是维持引用的,大概明白了,thx