我正在实现一个类库并寻找一种方法来限制该库将分配给预设数量的给定类的实例数量。限制必须是机器范围的——一个简单的static
计数器是不够的,因为它只会计算调用进程中的实例。我想让事情尽可能简单(没有内存映射文件等)和尽可能安全(没有在临时文件或注册表中存储计数器)所以决定尝试使用全局共享信号量作为“计数器”
public class MyClass : IDisposable
{
// Limit to 10 instances
Semaphore m_sem = new Semaphore(10, 10, "SharedName");
public MyClass()
{
if(!m_sem.WaitOne(0))
{
throw new Exception("No instances free");
}
}
void IDisposable.Dispose()
{
m_sem.Release();
}
}
这似乎工作正常。但是,如果Dispose()
没有被调用,则信号量永远不会被释放 - 本质上是“泄漏”实例。现在恕我直言IDisposable
,是 .NET 中最糟糕的部分之一——我发现丢失的代码using( ... ) {}
比使用它要多得多。更糟糕的是,当您使用 aIDisposable
作为数据成员并观察“IDisposable 癌症”在您的应用程序中的每个类中传播时。
所以我决定为IDisposable
忘记 using() 的人实现完整的(反)模式。
public class MyClass : IDisposable
{
// Limit to 10 instances
Semaphore m_sem = new Semaphore(10, 10, "SharedName");
public MyClass()
{
if(!m_sem.WaitOne(0))
{
throw new Exception("No instances left");
}
}
~MyClass()
{
Dispose(false);
}
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
void Dispose(bool disposing)
{
if(disposing)
{
m_sem.Release();
}
else
{
// To release or not release?
// m_sem.Release();
}
}
}
使用 正确调用时事情很简单using
,我释放了 semapore。但是,当被最终确定作为最后的手段时,据我所知,我不应该访问托管资源,因为销毁顺序不固定 - m_sem 可能已被销毁。
那么,在用户忘记的情况下如何释放信号量using
呢?(RTFM 可能是一个有效的答案,但我希望避免)。就目前而言,“泄漏”实例一直计数到使用我的程序集的最终进程终止(此时我假设全局信号量被释放)
或者确实有更好的方法来做到这一点?