多线程应用中静态全局非托管资源的管理
Posted
技术标签:
【中文标题】多线程应用中静态全局非托管资源的管理【英文标题】:Management of Static Global Unmanaged Resources in Multithreaded App 【发布时间】:2012-02-13 14:44:30 【问题描述】:我们遇到了一个资源管理问题,我们已经为此苦苦挣扎了几个星期,虽然我们终于找到了解决方案,但对我来说仍然很奇怪。
我们针对旧系统开发了大量互操作代码,这些系统公开了 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
【问题讨论】:
【参考方案1】:我在这里首先跳脚,因为对于您的特定代码库有很多未知数,但我想知道基于会话的方法是否有任何里程?您可以拥有一个(线程安全)会话工厂单例,负责确保仅初始化一个环境,并通过将其绑定到 ASP.NET AppDomain 和/或类似事件上的事件来适当地处置该环境。您需要将此会话模型烘焙到您的 API 中,以便所有客户端在进行任何调用之前首先建立一个会话。为这个答案的模糊性道歉。如果您可以提供一些示例代码,也许我可以给出更具体/详细的答案。
【讨论】:
这是一个合理的建议。我想我们正试图避免会话,以使每个呼叫尽可能无状态。我认为当会话意外终止时,我们很可能会遇到类似的问题。我很抱歉没有发布代码,但是发布代码是一个棘手的问题...... 如何使用 AOP 对 API 隐藏会话管理,从而使其看起来无状态?您可以拦截所有公共 API 调用,以确保在继续调用之前初始化环境。同样,将进程的生命周期绑定到客户端 AppDomain 的生命周期。我在这里抓住了稻草,但那是我的两便士价值。【参考方案2】:您可能要考虑的一种方法是为您的非托管组件创建一个隔离的 AppDomain。这样,当 IIS 托管的 AppDomain 被回收时,它就不会成为孤立对象。
【讨论】:
有趣...为什么 IIS 不也回收这个域? 我的理解是你可以回收一个 ASP.NET 应用程序(这是一个 AppDomain),例如通过“触摸” web.config 或 bin 文件夹中的文件。如果发生这种情况,我相信同一进程中的其他 AppDomain(例如其他 ASP.NET 应用程序)将继续运行。另一方面,如果应用程序池(IIS6 及更高版本)被回收,工作进程将被关闭并重新启动。您描述的问题表明该进程没有被回收,只有 AppDomain。以上是关于多线程应用中静态全局非托管资源的管理的主要内容,如果未能解决你的问题,请参考以下文章