gpt4 book ai didi

c# - 在 IDisposable 派生类中应该在哪里释放单例互斥量?

转载 作者:行者123 更新时间:2023-11-30 20:23:44 24 4
gpt4 key购买 nike

背景

我正在努力实现一个数据库访问器的派生类,它应该一次只允许一个线程访问数据库。 但是这个问题应该适用于使用 Disposable 模式的任何形式的单线程访问。

Stephen Cleary's blog他展示了如何使用 IDisposable 模式实现互斥体,这几乎就是这个想法。

关于 MSDN's website他们展示了如何在派生类中使用 IDisposable 模式。

在这个关于 best practices of SQlite db in android 的回答中建议打开 SQLite 数据库,永远不要关闭它,而是使用一种委托(delegate)来维护并发;我不喜欢这一点,但它让我想到了接下来的内容。

程序

如果多个线程试图访问它,则抛出异常的基类:

class BaseClass : IDisposable

实现锁的派生类:

class DerivedClass : BaseClass
{
private static Semaphore _mutex = new Semaphore(1, 5);

public DerivedClass
{
_mutex.WaitOne();
}

protected override void Dispose(bool disposing)
{
if (disposed)
return;

问题

应该在哪里调用 _mutex.Release()?在 base.Dispose() 之前还是之后?

选项 1:

 _mutex.Release();
disposed = true;
base.Dispose(disposing);

选项2:

 disposed = true;
base.Dispose(disposing);
_mutex.Release();

MSDN 说在调用 base.Dispose 之前释放任何非托管对象,这让人感觉释放也应该在之前发生,就像选项 1。而且它是 MSDN,我敢肯定他们最了解。

但是,选项 1 为线程在基类被 Disposed 之前访问基类打开了大门(至少看起来是这样)。这让我觉得选项 2 是正确的实现。

我已经尝试了这两种实现方式,并且都有效;但我不确定哪一个会继续工作。

能否请您也解释一下为什么会出现这种情况。

最佳答案

我发帖只是因为我非常不同意投票赞成的答案 :) 线程竞速错误是您可以处理的最讨厌的错误。极难调试,墨菲定律规定它们只会在您不调试应用程序时出现,并且每月仅随机出现一次。您永远无法对您的应用进行充分测试以 100% 确定您没有此类错误,您需要所有可获得的帮助来检测它们。

在另一个线程仍在使用对象时处置对象是一种不幸,这种情况并不少见。因此,当发生这种情况时,您必须尽可能地获得异常。 Super-duper 重要的是首先处理 Mutex,这最大限度地提高了获得 ODE 的几率。现在你知道你有一个错误。

这不是唯一的原因,通常您对基类的 Dispose() 方法知之甚少。它可能会抛出。当发生这种情况时,您真的不想“泄漏”互斥锁,当您无法控制的代码不够明智地捕获此类异常时,这只会造成更多麻烦。

遵循 Microsoft 指南的两个相当不错的理由。 .NET Framework 中的每个 Disposable(bool) 覆盖最后调用 base.Dispose() 方法。

关于c# - 在 IDisposable 派生类中应该在哪里释放单例互斥量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28166027/

24 4 0