线程退出 2010-11-18 19:42

Q我工作的一个应用程序包含一个用户界面线程和工作者线程。在某些时候,用户界面线程,可以通知用户该线程完成工作正在由工人应被终止。在我看来是最简单的方式做,这将是调用TerminateThread函数。但是看完了Win32 ® SDK的文档时,我很关注的问题,这可能的原因。 该文档国“TerminateThread是一个危险的功能,只应在案件中使用最极端的。”什么时候适合使用TerminateThread?它是应用程序中可以使用它之前终止一?我什么问题可能碰上?

山姆马林

一个作为一般则,避免调用TerminateThread。该文档是正确的,当它指出了几个潜在的问题,很值得他们更深入地钻研。

第一个问题是,该系统不会释放线程的堆栈,当线程被终止TerminateThread。其他线程可能访问侵犯值在线程的堆栈,如果栈被释放,这会引起其他线程访问。(书,第一次印刷我的高级的Windows,微软出版社,1995年,表明在65页的Windows ® 95不自由线程的堆栈时,该线程将被终止。这是真正的Windows 95早期测试版的,但不是最终发布版本。班),终止线程的堆栈将被释放的进程终止时,这样你的程序将泄漏内存只有在它正在运行。

用TerminateThread第二个问题是,到进程的地址空间映射的任何DLL不会得到通知。在一般情况下,你将无法知道具体后果的方式,但让我们考虑一些可能性。

当一个新线程被创建,目前所有DLL映射到进程得到通知到他们DllEntryPoint(或DllMain中)与DLL_THREAD_ATTACH函数在fdwReason参数传递调用。一个DLL应该执行它的线程特定的初始化时,收到此通知。当一个线程终止时,再次得到通知所有DLL与该fdwReason参数传递DLL_THREAD_DETACH。这为每个DLL的机会来执行它的线程特定的清理工作。然而,当一个线程是TerminateThread终止,映射DLL不得到DLL_THREAD_DETACH通知,因此,这些DLL是没有机会进行适当的清理。

如Microsoft ® C运行时DLL(MSVCRT40.DLL)某些DLL的,希望得到DLL_THREAD_DETACH通知。 微软的C运行时DLL使用此通知释放的内存块。当它没有收到此通知,因为该线程是TerminateThread终止,该内存块没有得到释放,直到该进程终止。另一个例子是一个DLL,数据刷新到磁盘文件当它接收到DLL_THREAD_DETACH通知。在这种情况下,使用TerminateThread会造成数据丢失。

用TerminateThread第三个问题是,它允许临界区和互斥被放弃。如果你不马上明白为什么这是非常不好的,例如要说服你。多线程C运行时DLL使用临界区,以保护其内部数据结构,例如malloc和免费使用临界区进入堆结构。为了防止被从多个线程同时访问损坏堆,C运行时DLL使用的关键部分。

试想,一个线程调用malloc,进而调用EnterCriticalSection。当EnterCriticalSection返回后,线程拥有的关键部分。现在,突然之间,该线程终止TerminateThread。在这一点上,关键的部分将被抛弃。在此过程中当其他线程调用malloc时,系统会迫使这些线程等待,直到被释放关键节。但是,这绝不会发生,正在等待的线程被暂停执行malloc的永远!这是一个很好的理由,以避免TerminateThread。

这个问题不仅限于像堆malloc和free函数。在C运行时DLL的许多功能没有得到充分的折返,因此需要用临界区保护。因此,如果您使用的是C运行时DLL的,它很难避免这个问题。

由于这一切,我喜欢无咖啡因可乐避免TerminateThread。如果你想拉从下一个线程(终止它),绝对最好的东西做出来的地毯是有杀人的线程通过调用ExitThread本身。下一个问题与此交易。

我会考虑使用TerminateThread只有当我需要终止一个线程,在做事情非常具有破坏性的(例如,一个线程从数据库中清除记录或格式化硬盘),而且没有其他办法我停止线程。

最后一个注意:许多开发者不正当地使用TerminateThread作为一个进程的关闭程序的一部分。要终止一个过程,这个过程中的任何线程可以(也应该)调用ExitProcess。

Q我有一个图形渲染应用程序。它包含一个用户界面线程仍然在运行过程的持续时间。当用户请求图形操作耗时从菜单一定的时间,第二个线程创建实际执行该操作。这样可以使用户界面的响应。我也想让用户取消请求的操作。这意味着我的用户界面线程必须以某种方式终止工作线程。工作线程的源代码是不是我的控制下,并修改它是困难的。有一个很好的方法来终止我的工作线程?

此处包含的信息发布未经Microsoft的认可。微软不保证其准确性或资料的完整性不做任何保证。读者表示,他们使用自己承担风险的信息。

我明白这个问题很多。Win32的不提供一种方式来标志一个工作线程终止,除非你想要的线程终止正在运行的消息循环。如果是,您可以以下行终止工人通过执行:

 PostThreadMessage(
   dwThreadIdWorker,WM_QUIT,(的WPARAM)nExitCode,0);

通常,这将导致消息循环退出,从而应使线程退出。如果你希望具有更高优先级的消息发送和你有一个处理由工作线程创建的窗口,您可以执行以下行:

 SendNotifyMessage(
   HWND的,WM_QUIT,(的WPARAM)nExitCode,0);

与使用PostThreadMessage或SendNotifyMessage问题是工作线程通常没有消息循环,这些功能都没有帮助。最简单的事情在这种情况下是使用一个设置由用户界面线程和工作者线程检查标志。例如,你可以创建一个全球性的标志:

 挥发性布尔g_fStopWorkerThread = 0;

并有检查工作线程不时的标志:

 如果(g_fStopWorkerThread)
   ExitThread(dwExitCode);

然后从用户界面线程,你可以设置标志:

 g_fStopWorkerThread =真;

这种方法简单,它赋予了它退出时,工作线程控制。这一点很重要,因为它可以防止在一个不应该被打断,如文件更新或对malloc的调用,操作过程中终止线程。主要缺点是,你必须洒上工作线程的代码,退出标志检查,除非有一个主处理循环在一个单一的检查可以走了。根据你的情况,因为这是你难以修改工作线程的代码,你将无法使用此方法。

读者谁问的问题还包括以下更多细节。然后用户界面线程产卵的工作线程,UI线程分配两个缓冲器输入一个,其他方面的输出。现在,怎么样缓冲?如果UI线程释放它分配的缓冲区,而工作线程仍在运行?最终,工作线程将试图引用其输入或输出缓冲区,此时一个访问冲突异常会引发造成线程终止。实际上,任何时候,工作线程中引用的缓冲区,这亦是检查请求终止。

以此作为标志以这种方式存储,你必须分配和释放的缓冲区使用VirtualAlloc和VirtualFree,以确保是decommitted时释放的,你不能使用malloc和释放内存。既然你不希望系统显示一个消息框当工作线程获取accessviolation,因此大受看守访问到内部的结构化异常处理__try块的缓冲区。如果youcannotmodify工作线程的代码,你必须创建一个包装函数调用工作线程的函数:

 的DWORD WINAPI WorkerThreadWrapper(PVOID pvParam){
   的DWORD dwExitCode = 0;
   __try {
      dwExitCode = WorkerThread(pvParam);
   }
   __except((GetExceptionCode()== EXCEPTION_ACCESS_VIOLATION)?
                           EXCEPTION_EXECUTE_HANDLER:EXCEPTION_CONTINUE_SEARCH){
   }
   返回(dwExitCode);
}

此包装函数允许访问冲突是没有任何变化引起工人本身的功能。作为一个额外的奖金,当异常过滤器返回EXCEPTION_EXECUTE_HANDLER,正常的C + +异常处理机制正常执行,导致析构函数对所有基于堆栈的C + +的工作线程函数创建对象调用。 因此,您需要注意的析构函数参考确保没有被释放的缓冲区,否则你会生成在C + +析构一个例外。 这将导致对C运行时DLL的函数调用而终止,默认情况下,终止该进程(不仅仅是线程)。

这个解决方案制定后我想到我怎么可能使其更为普遍。释放内存,一个工人线程使用将最终导致一个异常中提出的工作线程。如果我能找到某种机制来提高一个线程在另一个例外,我将能够终止缓冲释放任何工作线程,而无需。理想我是这样找一个Win32 API的调用,也许RaiseThreadException,像RaiseException的工作,但增加了一个线程句柄参数来指定线程什么像英寸提高系统供电异常,因为没有,我设计了一个方法来实现它。我用这个解决方案来建立自己的图书馆我的任何时间的功能,允许一个控制线程“干净”线程在终止工作者(嗯,几乎任何时间)。这种库称为KillThrd(见12)。这种方法只能在Windows NT下工作ª。 它不能在Windows 95的原因是过于复杂此栏深入研究。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值