你如何处理挂断电话的线程?

时间:2009-06-10 22:25:47

标签: c# .net asp.net multithreading

我有一个线程,并尝试建立连接。在线程中,我打电话给第三方库。有时,此调用会挂起,并且永远不会返回。在UI线程上,我希望能够通过中止线程来取消连接尝试,该线程应该中止对第三方库的挂起调用。

我已调用Thread.Abort,但现在已经读过Thread.Abort仅在控件返回托管代码时才有效。我观察到这是真的,因为线程永远不会中止,我现在已经坐在Thread.Join上十分钟了。我该怎么办这个挂线程?我应该将引用置空并继续吗?我想尽可能保持清洁 -

5 个答案:

答案 0 :(得分:4)

随机思考:我想知道你是否可以将第二个程序集编写为执行此通信的小型控制台exe ...使用Process.Start启动它并通过文件系统或拦截stdout捕获结果。然后,如果它挂起,你可以杀死这个过程。

有点苛刻,也许 - 显然它有产生过程的开销 - 但它至少应该可以杀死它。

答案 1 :(得分:3)

您的第三方库中的此功能没有超时取消功能?如果是这样,这是非常糟糕的设计。这里没有任何漂亮的解决方案,可以解决......

不幸的是,除了使用Win32 API手动终止线程之外,你无法绕过它,这当然会变得干净。但是,如果这个第三方库没有给你任何其他选项,那可能就是这样做的。 TerminateThread功能是您想要使用的功能,但请遵守警告!要获取要传递给此函数的线程ID,您必须使用另一个Win32 API调用(Thread类不直接公开它)。这里的方法是在托管线程方法的开头将volatile变量的值设置为GetCurrentThreadId的结果,然后稍后使用该线程ID来终止线程。

答案 2 :(得分:2)

不确定这样做是否可以接受,但是值得一试。

[DllImport("kernel32.dll")]
private static extern bool TerminateThread (Int32 id, Int32 dwexit);

来自documentation

TerminateThread是一个危险的函数,只能在最极端的情况下使用。只有当您确切知道目标线程正在执行的操作时,才应调用TerminateThread,并且您可以控制目标线程在终止时可能正在运行的所有代码。例如,TerminateThread可能会导致以下问题:

  • 如果目标线程拥有临界区,则不会释放临界区。
  • 如果目标线程正在从堆中分配内存,则不会释放堆锁。
  • 如果目标线程在终止时正在执行某些kernel32调用,则线程进程的kernel32状态可能不一致。
  • 如果目标线程正在操纵共享DLL的全局状态,则DLL的状态可能会被破坏,从而影响DLL的其他用户。

答案 3 :(得分:1)

托管线程无法直接停止本机线程。因此,如果调用在本机代码中被阻止,那么您可以做的最好的事情就是让托管线程检查,然后在它返回后终止。如果它永远不会返回,也许有一个带有timemout的呼叫版本?

如果没有,杀死线程(通过win32)通常不是一个好主意......

答案 4 :(得分:-1)

不能无限期地等待线程(任何语言),特别是如果您正在进行外部呼叫,这不是一个好的解决方案。始终使用具有超时的联接,或者使用自旋锁来监视共享原子变量的状态,直到它发生更改,或者达到超时。我不是C#人,但这些都是合理的并发实践。