需要击败GC并且一旦超出范围就将对象销毁

Dav*_*ave 4 c# garbage-collection locking

我需要使用Mutex保护几段代码.问题是代码看起来像这样:

lock(mylockobject) {
  if(!foo())
    throw new MyException("foo failed");
  if(!bar())
    throw new MyException("bar failed");
}
Run Code Online (Sandbox Code Playgroud)

使用锁,它可以按照我的意愿工作,但现在我需要使用互斥锁.这里显而易见的问题是,如果我获取互斥锁并且foo()或bar()失败,我将不得不在抛出每个异常之前释放互斥锁.

在C++中,我将利用在堆栈上创建的对象的范围,并将互斥锁定在对象的构造函数中,然后在析构函数中释放它.使用.NET的垃圾收集,我认为这不会起作用.我写了一个测试应用程序,并确认如果我做这样的事情:

public class AutoMutex
{
  private Mutex _mutex;
  public AutoMutex(Mutex mutex)
  {
     _mutex = mutex;
     _mutex.WaitOne();
  }

  ~AutoMutex()
  {
    _mutex.ReleaseMutex();
  }
}
Run Code Online (Sandbox Code Playgroud)

然后有这样的代码:

// some code here...
Mutex my_mutex = new Mutex(false, "MyMutex");
{ // scoping like I would do in C++
  AutoMutex test = new AutoMutex(my_mutex);
  test = null;
}
Run Code Online (Sandbox Code Playgroud)

析构函数(终结器?)直到很久才被调用.

谷歌还没有指出我正确的方向,但我还在努力......请让我知道如何解决这个小问题,如果可能的话.

Eri*_*ert 16

情侣点.

1)你想要搜索的东西是"一次性模式".要非常小心地正确实现它.当然,Mutex 已经实现了一次性模式,所以我不清楚为什么你想要自己创造,但是,它仍然是很好的学习.

有关使用一次性模式是否明智的一些额外想法,请参阅此问题,就像它是RAII一样:

是否滥用IDisposable和"使用"作为获取异常安全的"范围行为"的手段?

2)Try-finally也有你想要的语义.当然,"使用"块只是try-finally的语法糖.

3)你确定要在抛出某些内容时释放互斥锁吗?你确定要扔进受保护的区域吗?

由于以下原因,这是一种糟糕的代码味道.

为什么你首先有一个互斥?通常因为模式如下:

  • 国家是一贯但陈旧的
  • 锁定访问状态
  • 使状态不一致
  • 使国家保持一致
  • 解锁对州的访问权限
  • 现在状态一致而且新鲜

考虑在"使状态保持一致"之前抛出异常时会发生什么. 您解锁对状态的访问,该状态现在不一致且陈旧.

保持锁定可能是个更好的主意.是的,这意味着冒着死锁的风险,但至少你的程序不是在垃圾,陈旧,不一致的状态下运行.

从一个受锁保护的区域内部抛出异常是一个可怕而可怕的事情,你应该尽可能避免这样做.从锁内抛出的异常,使你有两个可怕的事情之间做出选择:要么你得到死锁,或你变得疯狂崩溃和不可再现的行为,当你的程序操纵不一致的状态.

你真正应该实施的模式是:

  • 国家是一贯但陈旧的
  • 锁定访问状态
  • 使状态不一致
  • 使国家保持一致
  • 如果发生异常,则回滚到陈旧,一致的状态
  • 解锁对州的访问权限
  • 现在状态是一致的,如果没有例外,那就是新鲜的

这是更安全的替代方案,但编写执行此类交易的代码非常困难.没有人说多线程很容易.


Mar*_*lin 12

为了提供范围,你可以制作你的AutoMutex工具IDisposable并使用它:

using(new AutoMutex(.....))
{
  if(!foo())
    throw new MyException("foo failed");
  if(!bar())
    throw new MyException("bar failed");
}    
Run Code Online (Sandbox Code Playgroud)

在您的实现中IDisposable.Dispose(),释放互斥锁.


n8w*_*wrl 9

Mutex实现了IDisposable,因此将其包装在一个 using

using (Mutex m = new Mutex())
{
   //Use mutex here

}
//Mutex is out of scope and disposed
Run Code Online (Sandbox Code Playgroud)

  • 它是,Mutex扩展了Waithandle,它实现了IDisposable.耶继承! (2认同)

tva*_*son 7

使用try/finally块或使用IDisposable模式并将您的用法包装在using语句中.