【问题标题】:Using AppDomains to Parallelize Non-thread-safe DLL使用 AppDomains 并行化非线程安全的 DLL
【发布时间】:2011-05-15 21:52:26
【问题描述】:

我有一个非托管 C++ DLL,我的 .NET 应用程序通过 p/invoke 使用它。我需要来自这个 DLL 的方法相当耗时,我想并行化方法调用。问题是它使用了一堆静态变量和全局变量,因此它不是线程安全的(并且无法更改)。我的计划是通过从多个 AppDomain 并行调用非托管 DLL 来克服这个非线程安全问题。

只要我不并行调用,我就可以毫无问题地从多个 AppDomain 调用非托管代码,但是一旦并行调用,我就会得到一个AccessViolationException。我正在使用 Parallel.For() 进行并行调用。

是否可以通过简单地从多个 AppDomain 进行调用来使非线程安全的非托管 DLL “线程安全”?

【问题讨论】:

  • 对于不能很好地使用多线程的非托管 DLL,恕我直言,进程隔离比 appdomains容易得多

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


【解决方案1】:

从多个AppDomain 实例调用本机方法对您毫无帮助。 AppDomain 边界不适用于本机 DLL,它们不会提供任何好处

【讨论】:

    【解决方案2】:

    首先:Load multiple copies of dll in same process

    您必须确保 AppDomain 中的所有调用都在一个线程上。

    ParallelFor 无法做到这一点,因此您需要

    • 手动并行化(为每个线程/应用程序域分块循环)
    • 更好(恕我直言):编写一个包装函数,该函数将使用本机 dll 的特定实例(例如,通过使用来自线程本地存储的 AppDomain 的引用?)。

    请注意,根据您的情况的复杂性(回调、在托管库中使用全局数据),您可能希望将每个 AppDomain 的执行限制为特定的 CPU 核心(核心关联:请参阅Begin/EndThreadAffinity)。我在这里可能有点偏执:)

    【讨论】:

    • 这是一个有趣的想法,我会尝试。那么,如果我加载同一个 DLL 的多个副本,为什么每个实例都需要从同一个线程中调用呢?
    • 就像我说的那样(接近)偏执狂。从技术上讲,代码可能依赖于 CPU 本地缓存;我需要在这里重新阅读一些文档,因为我现在对上下文切换的记忆非常模糊。可以这么说,在这种情况下,我希望本机 DLL 能够管理它自己的线程关联,因为这个问题根本不限于在 .NET 应用程序中使用)。所以:别担心:)
    • 由于本机DLL(native.dll)使用全局和静态变量,当我加载native1.dll、native2.dll、native3.dll等时,这些变量的多个副本会在内存中创建吗?所以我可以并行使用它们?
    • @dewald:是的。也就是说,正常情况下。所有动态分配都是......无论如何都是动态的,并且数据段是由于您正在加载图像的实际副本而被复制的。唯一会让你感到困惑的是命名管道、共享内存映射和进程间同步原语的使用;您可以看到正在使用的内容,例如process explorerhandle。一定要弄清楚你自己的应用使用什么来对比
    【解决方案3】:

    将 C++ DLL 包装在 EXE 中并并行化进程调用(而不是在线程或 AppDomain 中运行此代码)。我在 GeckoFX 上遇到了这个问题,它不喜欢线程,而且这个解决方案工作得很好。当然,由您来管理与这些进程的通信。我前段时间blogged about this

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-20
      • 2011-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多