2010-04-05 39 views
2

这里是场景:我应该使用IDisposable进行纯管理资源吗?

我有一个对象叫Transaction需要确保只有一个实体有权限在任何给定的时间编辑它。

为了促进长时间的锁定,我有类生成一个令牌对象,可用于进行编辑。

你会使用这样的:

var transaction = new Transaction(); 

using (var tlock = transaction.Lock()) 
{ 
    transaction.Update(data, tlock); 
} 

现在,我希望TransactionLock类来实现IDisposable使得它的使用可以明确。但是,我没有任何非托管资源可供处理。然而,在CLR不知道如何正确定位它的意义上,TransctionLock对象本身就是一种“非托管资源”。

所有这一切都会很好,我会只使用IDisposable并完成它。

不过,我的问题是当我尝试这样做的终结:

~TransactionLock() 
{ 
    this.Dispose(false); 
} 

我想终结从锁定解除交易,如果可能的话。 如何在终结器中检测父交易(this.transaction)是否已完成?

有没有更好的模式,我应该使用?

此外,Transaction类本身不必是一次性的,因为它不保留对锁的引用,并且不在乎它是否在去到坟墓时被解锁。


Transaction类看起来是这样的:

public sealed class Transaction 
{ 
    private readonly object lockMutex = new object(); 

    private TransactionLock currentLock; 

    public TransactionLock Lock() 
    { 
     lock (this.lockMutex) 
     { 
      if (this.currentLock != null) 
       throw new InvalidOperationException(/* ... */); 

      this.currentLock = new TransactionLock(this); 
      return this.currentLock; 
     } 
    } 

    public void Update(object data, TransactionLock tlock) 
    { 
     lock (this.lockMutex) 
     { 
      this.ValidateLock(tlock); 

      // ... 
     } 
    } 

    internal void ValidateLock(TransactionLock tlock) 
    { 
     if (this.currentLock == null) 
      throw new InvalidOperationException(/* ... */); 

     if (this.currentLock != tlock) 
      throw new InvalidOperationException(/* ... */); 
    } 

    internal void Unlock(TransactionLock tlock) 
    { 
     lock (this.lockMutex) 
     { 
      this.ValidateLock(tlock); 

      this.currentLock = null; 
     } 
    } 
} 

而且Dispose(bool)代码为TransactionLock

private void Dispose(bool disposing) 
{ 
    if (disposing) 
    { 
     if (this.Transaction != null) 
     { 
      this.Transaction.Unlock(this); 
      this.Transaction = null; 
     } 
    } 
} 
+0

在什么情况下可以了'TransactionLock'现实没有'已经在其名为Dispose'被抛弃?我看不到任何情况下终结者能够做任何有用的事情。 – supercat 2012-06-28 18:30:11

回答

2

这是discussed before。你的情况要容易得多,你也要实现终结器。这是根本错误的,你在客户端代码中隐藏了一个bug。请注意,终结器在单独的线程上运行。调试一致的死锁要比处理随机和异步消失的锁容易得多。

建议:遵循.NET框架铅:不帮助太多。出于同样的原因,微软放弃了Synchronized方法。

+0

这不像前面提到的那样相当*。在我的情况下,被放置的令牌对象实际上被用作验证机制,并且需要进行适当的清理。在我的场景中需要继续的阶段与本地句柄完全相同。 – 2010-04-05 22:50:13

+0

好的,那么,有没有什么办法可以在没有实际实现'IDisposable'的情况下得到'使用'类语义?我很确定没有答案。在那种情况下,是否有任何方法可以确定性地触发终结器? – 2010-04-05 23:04:25

+0

另外,我刚刚发布了我的Dispose代码,正如您所看到的那样,它并未解锁(因为我无法证明事务是否已完成)。这意味着这将导致你提到的一致的死锁(或者,实际上,InvalidOperationException)。实际上这意味着我的终结者总是浪费,因为它从来没有实际的处置。我会*要*它来处理锁,但我想,正如你所建议的,那是“帮助太多”... – 2010-04-05 23:10:21

1

如何,在终结,做我检测是否 父母交易 (this.transaction)已经是 最终确定?

这可以通过在Transaction中保留_disposed布尔型字段并通过IsDisposed只读属性公开它。这是标准做法。

~TransactionLock() 
    { 
     this.Dispose(false); 
    } 

是否有更好的方式我应该用 ?

如果事务锁定没有非托管资源是正确的,那么就省略析构函数(终结器)。它没有功能,但确实有很高的成本。

编辑:如果我读正确,解锁不会TransactionLock链接切断通讯交易,这意味着一个老锁的Dispose(布尔)将被称为尽管析构函数。目前还不清楚这是否安全。

的问题会更完整与TransactionLock.Dispose(bool)


而且一下代码,交易类本身 不必是一次性的,因为它 不维护的一个参考 锁,并不在乎是否 是解锁,当它进入 坟墓。

由此可见,当收集到一个TransactionLock时,它只能持有一个正在收集的事务的引用。不需要在这里干扰析构函数,这不会解决任何问题,只会产生你不需要的问题。

+0

它切断链接。将发布代码... – 2010-04-05 20:57:40

+0

我猜想,那么我真正想要做的是通过强制(或者,提示)Dispose()而不是使用Destructor/Finalizer来模拟C#中的RAII。有没有一种方法来实现当对象超出范围时立即调用的终结器? – 2010-04-05 22:53:30

+0

@John:对于RAII,只需实现Dispose()并使用'using'。仍然不需要析构函数。 – 2010-04-06 10:14:06

相关问题