多线程应用程序中静态全局非托管资源的管理

本文关键字:资源 管理 应用程序 静态 全局 多线程 | 更新日期: 2023-09-27 18:24:27

我们遇到了一个资源管理问题,我们已经挣扎了好几个星期了,虽然我们终于找到了解决方案,但对我来说仍然很奇怪。

我们有大量针对遗留系统开发的互操作代码,该遗留系统公开了一个C API。该系统的许多特性之一是(由于未知的原因),在使用API之前,必须初始化"环境",该"环境"似乎是经过处理的。然而,它只能初始化一次,并且必须在完成后"关闭"

我们最初使用单例模式来实现这一点,但当我们在IIS托管的web服务中使用此系统时,我们的AppDomain偶尔会被回收,从而导致"孤立"环境泄漏内存。由于终结和(显然)甚至IIS回收都是不确定的,在所有情况下都很难检测到,我们已经切换到了一种似乎运行良好的处置+引用计数模式。然而,手动进行引用计数感觉很奇怪,我相信还有更好的方法。

在这样的环境中管理一个静态的全球可支配资源有什么想法吗?

以下是环境管理的大致结构:

public class FooEnvironment : IDisposable
{
  private bool _disposed;
  private static volatile int _referenceCount;
  private static readonly object InitializationLock = new object();
  public FooEnvironment()
  {
    lock(InitilizationLock)
    {
      if(_referenceCount == 0)
      {
        SafeNativeMethods.InitFoo();
        _referenceCount++;
      }
    }
  }
  public void Dispose()
  {
    if(_disposed)
      return;
    lock(InitilizationLock)
    {
      _referenceCount--;
      if(_referenceCount == 0)
      {
        SafeNativeMethods.TermFoo();
      }
    }
    _disposed = true;
  }
}
public class FooItem
{
  public void DoSomething()
  {
    using(new FooEnvironment())
    {
      // environment is now initialized (count == 1)
      NativeMethods.DoSomething();
      // superfluous here but for our purposes...
      using(new FooEnvironment())
      {
        // environment is initialized (count == 2)
        NativeMethods.DoSomethingElse();
      }
      // environment is initialized (count == 1)
    }
    // environment is unloaded
  }
}

多线程应用程序中静态全局非托管资源的管理

我首先站起来,因为关于您的特定代码库有很多未知之处,但我想知道基于会话的方法有什么好处吗?您可以有一个(线程安全)会话工厂单例,负责确保只初始化一个环境,并通过将其绑定到ASP.NET AppDomain和/或类似平台上的事件来适当地处理该环境。您需要将此会话模型烘焙到API中,以便所有客户端在进行任何调用之前首先建立会话。对这个答案的含糊表示歉意。如果你能提供一些示例代码,也许我可以给出一个更具体/详细的答案。

您可能需要考虑的一种方法是为非托管组件创建一个独立的AppDomain。这样,当IIS托管的AppDomain被回收时,它就不会孤立。