线程错误:当尝试释放挂起的线程时,句柄无效(6) [英] Thread Error: The Handle is Invalid (6) when trying to Free a suspended thread

查看:286
本文介绍了线程错误:当尝试释放挂起的线程时,句柄无效(6)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在给定的例子中,当调用 AThread.Free时收到异常。

 code>程序Project44; 

{$ APPTYPE CONSOLE}

使用
SysUtils,Classes,Windows;

type
TMyException = class(Exception);

var
AThread:TThread;
begin
AThread:= TThread.Create(True);
try
AThread.FreeOnTerminate:= True;
//我想在开始线程之前做一些事情
//在设置阶段有一些异常可能会发生,这个异常是为了模拟purpouses
raise TMyException.Create('exception' );
除了
AThread.Free; //另一个异常
end;
结束。

我有两个问题:


  1. 在给定的示例中,如何释放 AThread c> TThread p>


  2. 我不明白为什么 TThread.Destroy 正在调用简历在破坏自己之前。这是什么意思?



解决方案

code> FreeOnTerminate True 调用免费在线程实例上。你必须做一个或另一个,但不是两个。因为你的代码破坏了线程两次。你绝对不能破坏一个对象两次,当然,当析构函数运行第二次时,会发生错误。



这里发生的是,由于你创建的线程被暂停,直到你明确释放线程才发生。当你这样做时,析构函数恢复线程,等待它完成。再次调用 Free ,因为您将 FreeOnTerminate 设置为 True 。第二次调用 Free 关闭句柄。然后你返回线程proc,并调用 ExitThread 。因为线程的句柄已经关闭,所以失败。



正如Martin在评论中指出的那样,您不能创建 TThread 直接由于 TThread.Execute 方法是抽象的。此外,您不应使用不推荐使用的简历。使用开始开始执行挂起的线程。



我个人不喜欢使用 FreeOnTerminate 。使用此功能会导致线程在与其创建的不同线程上销毁。当您想要忘记实例引用时,通常使用它。那么那么让你不确定线程​​是否在你的进程终止时被破坏,或者甚至是在进程终止时终止并释放它。



如果你必须使用 FreeOnTerminate ,那么您需要确保在设置 Free > FreeOnTerminate 到 True 。所以明显的解决办法是在调用开始 FreeOnTerminate 设置为 True c $ c>然后忘记线程实例。如果您在准备开始之前有任何例外,那么您可以安全地释放线程,因为您 FreeOnTerminate 仍然是 False 在那一点。

 线程:= TMyThread.Create(True); 
尝试
//初始化线程对象

Thread.Free;
加注
结束;
Thread.FreeOnTerminate:= True;
Thread.Start;
线程:= nil;

更优雅的方法是将所有初始化转移到 TMyThread 构造函数。那么代码将如下所示:

 线程:= TMyThread.Create(True); 
Thread.FreeOnTerminate:= True;
Thread.Start;
线程:= nil;


In a given example I am receiving an exception when calling AThread.Free.

program Project44;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, Windows;

type
  TMyException = class(Exception);

var
  AThread: TThread;
begin
  AThread := TThread.Create(True);
  try
    AThread.FreeOnTerminate := True;
    //I want to do some things here before starting the thread
    //During the setup phase some exception might occur, this exception is for simulating purpouses
      raise TMyException.Create('exception');
  except
    AThread.Free; //Another exception here
  end;
end.

I have two questions:

  1. How should I free AThread instance of TThread in a given example?

  2. I don't understand, why TThread.Destroy is calling Resume before destroing itself. What is the point of this?

解决方案

You can't set FreeOnTerminate to True and call Free on the thread instance. You have to do one or the other, but not both. As it stands your code destroys the thread twice. You must never destroy an object twice and of course when the destructor runs for the second time, errors occur.

What happens here is that since you created the thread suspended, nothing happens until you explicitly free the thread. When you do that the destructor resumes the thread, waits for it to complete. This then results in Free being called again because you set FreeOnTerminate to True. This second call to Free closes the handle. Then you return to the thread proc and that calls ExitThread. This fails because the thread's handle has been closed.

As Martin points out in the comment you must not create TThread directly since the TThread.Execute method is abstract. Also, you should not use Resume which is deprecated. Use Start to begin execution of a suspended thread.

Personally I don't like to use FreeOnTerminate. Using this feature results in the thread being destroyed on a different thread from which it was created. You typically use it when you want to forget about the instance reference. That then leaves you uncertain as to whether or not the thread has been destroyed when your process terminates, or even whether it is terminating and freeing itself during process termination.

If you must use FreeOnTerminate then you need to make sure that you don't call Free after having set FreeOnTerminate to True. So the obvious solution is to set FreeOnTerminate to True immediately before after calling Start and then forget about the thread instance. If you have any exceptions before you are ready to start then you can safely free the thread then since you FreeOnTerminate would still be False at that point.

Thread := TMyThread.Create(True);
Try
  //initialise thread object
Except
  Thread.Free;
  raise;
End;
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;

A more elegant approach would be to move all the initialisation into the TMyThread constructor. Then the code would look like this:

Thread := TMyThread.Create(True);
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;

这篇关于线程错误:当尝试释放挂起的线程时,句柄无效(6)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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