【问题标题】:How to handle blocking synchronous external DLL methods如何处理阻塞同步外部 DLL 方法
【发布时间】:2012-10-12 07:55:15
【问题描述】:

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

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

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

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

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

即使这不是最佳做法,我能否解决此问题? 任何不好的黑客表示赞赏:)

【问题讨论】:

  • 为什么需要 AppDomain?为什么不确定在单独的线程中运行您需要做的任何事情?如果线程挂起并且你想要一个肮脏的黑客然后使用thread.Abort()
  • 这是我早期的方法。但是即使在调用 Abort 之后线程也没有被杀死,所以我推测我在 AppDomains 上有更多的硬杀死可能性
  • @wal Thread.Abort 不起作用,在本机调用中唯一可以使用的是TerminateThread,而您真的不想调用它。另见How to kill a thread in C# effectively?。您应该考虑将线程保留为僵尸 - 除非它是一个长时间运行的进程或该线程正在消耗 CPU 时间,否则放弃它不会造成太大的伤害。

标签: c# .net com parallel-processing appdomain


【解决方案1】:

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

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

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

【讨论】:

  • 感谢您的解释。我不想使用进程,因为它是一个可以部署到多个服务器的 ASP.NET 应用程序。所以我不得不为权利而烦恼。此外,我必须多次调用此外部方法并将其托管在单独的进程中肯定不会提高性能,因为它已经没有我想要的那么快。无论如何,它似乎是唯一的解决方案(我能做到),所以我可以试一试。感谢您的帮助!
【解决方案2】:

在阅读this 之后(向下滚动到阻塞问题的末尾)我认为您唯一的解决方案是在不同的进程中运行该方法 - 这可能涉及相当多的重构和/或一个“宿主”项目(例如控制台应用程序),它在使用Process 类启动新进程时加载相关方法并使其易于调用(例如从命令行读取参数)

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-01
      • 2018-04-06
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      • 1970-01-01
      相关资源
      最近更新 更多