最近我使用外部dll库,我对它没有任何影响。 在某些特殊情况下,这个第三方dll的方法是阻塞而且永远不会返回。
我试图通过在新的AppDomain中执行此方法来解决此问题。在自定义超时后,我想卸载AppDomain并杀死所有这些垃圾;)
不幸的是,它不起作用 - 正如有人所期望的那样。
经过一段时间后,它会抛出CannotUnloadAppDomainException,因为阻塞方法不允许正常中止线程。
我依赖于使用这个库,似乎不会很快发布更新。
即使这不是最佳做法,我也可以解决这个问题吗? 任何坏的黑客都赞赏:)
答案 0 :(得分:5)
AppDomain通常无法解决该问题,只能丢弃程序的状态。真正的问题是你的线程被卡住了。在这种情况下,调用Thread.Abort()不太可能工作,它也会被卡住。如果线程是“可警告的等待状态”,则只能在CLR同步对象上阻塞线程。或者执行托管代码。在CLR知道如何安全清理的状态下。在执行非托管代码时,大多数第三方代码都会像这样崩溃,无法以安全的方式清理它。这种情况的决定性暗示是AppDomain.Unload无法完成工作,它只能在可以中止正在域中执行代码的线程时卸载AppDomain。
唯一的好选择是在单独的进程中运行该代码。你可以使用Process.Kill()杀死它。 Windows进行清理。您将使用.NET互操作机制与该代码进行通信。像命名管道,套接字,远程处理或WCF。另外,处理编写可以检测超时的代码导致进程崩溃的麻烦,启动备份并恢复内部状态,因为现在重新启动了第三方代码的未初始化实例。
不要忘记真正的修复。创建一个可以重现问题的小型repro项目。当它挂起时,创建一个进程的minidump。将两者发送给第三方支持小组。
答案 1 :(得分:3)
阅读this后(向下滚动到阻止问题)我认为你唯一的解决方案是在不同的进程中运行该方法 - 这可能涉及相当多的重构和/或一个'主机'项目(例如控制台应用程序),它使用Process
类
答案 2 :(得分:1)
您始终可以使用后台工作程序,无需创建新的应用程序域。这将确保您完全控制线程的执行。
但是,无法确保您可以优雅地中止线程。由于dll是不受管理的,因此可能会导致内存泄漏。但是,生成一个新线程将确保您的应用程序不会在Dll没有响应时崩溃。