2

最近我使用了一个外部 dll 库,对此我没有任何影响。在某些特殊情况下,这个第三方dll的一个方法是阻塞的,永不返回。

我试图通过在新的 AppDomain 中执行此方法来解决此问题。自定义超时后,我想卸载 AppDomain 并杀死所有这些废话;)

不幸的是,它不起作用 - 正如有人所期望的那样。

一段时间后,它会抛出 CannotUnloadAppDomainException,因为阻塞方法不允许优雅地中止线程。

我依赖于使用这个库,而且似乎不会很快有更新。

所以我可以解决这个问题,即使它不是最佳实践?任何不好的黑客表示赞赏:)

4

3 回答 3

5

AppDomain 通常不能解决该问题,最好丢弃程序的状态。真正的问题是你的线程被卡住了。在这种情况下,调用 Thread.Abort() 不太可能起作用,它也会卡住。一个线程只有在它处于“可提醒等待状态”时才能被中止,阻塞在 CLR 同步对象上。或执行托管代码。在 CLR 知道如何安全清理的状态下。大多数第 3 方代码在执行非托管代码时都会像这样崩溃,无法以安全的方式清理它。这种情况的一个决定性提示是 AppDomain.Unload 未能完成工作,它只能在可以中止正在执行域中的代码的线程时卸载 AppDomain。

唯一好的选择是在单独的进程中运行该代码。你可以用 Process.Kill() 杀死它。Windows 进行清理。您将使用 .NET 互操作机制与该代码对话。像命名管道、套接字、远程处理或 WCF。加上编写可以检测超时的代码的相当大的麻烦会杀死进程,启动它并恢复内部状态,因为您现在使用该第 3 方代码的未初始化实例重新启动。

不要忘记真正的修复。创建一个重现问题的小型重现项目。当它挂起时,创建进程的小型转储。将两者都发送到第 3 方支持小组。

于 2012-10-22T14:36:27.087 回答
3

读完这篇文章后(向下滚动到阻塞问题),我认为您唯一的解决方案是在不同的进程中运行该方法- 这可能涉及相当多的重构和/或加载的“主机”项目(例如控制台应用程序)有问题的方法,并且在使用Process该类启动新进程时易于调用(例如从命令行读取 args)

于 2012-10-22T14:19:12.433 回答
1

您始终可以使用后台工作人员,无需创建新的应用程序域。这将确保您完全控制线程的执行。

但是,没有办法确保您可以优雅地中止线程。由于 dll 是非托管的,因此可能会导致内存泄漏。但是,产生一个新线程将确保您的应用程序在 Dll 没有响应时不会崩溃。

于 2012-10-22T13:45:36.607 回答