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(),释放互斥锁.
Mutex实现了IDisposable,因此将其包装在一个 using
using (Mutex m = new Mutex())
{
//Use mutex here
}
//Mutex is out of scope and disposed
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
744 次 |
| 最近记录: |