我有几段代码需要用互斥锁来保护。问题是代码看起来像这样:
lock(mylockobject) {
if(!foo())
throw new MyException("foo failed");
if(!bar())
throw new MyException("bar failed");
}
使用锁,它可以按我想要的方式工作,但现在我需要使用互斥体。这里明显的问题是,如果我获取互斥体并且 foo() 或 bar() 失败,我必须在抛出每个异常之前显式释放互斥体。
在 C++ 中,我将利用在堆栈上创建的对象的范围,并将互斥锁锁定在对象的构造函数中,然后在析构函数中释放它。对于 .NET 的垃圾收集,我认为这行不通。我编写了一个测试应用程序并确认如果我执行以下操作:
public class AutoMutex
{
private Mutex _mutex;
public AutoMutex(Mutex mutex)
{
_mutex = mutex;
_mutex.WaitOne();
}
~AutoMutex()
{
_mutex.ReleaseMutex();
}
}
然后有这样的代码:
// 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;
}
析构函数(终结器?)直到很久以后才会被调用。
谷歌还没有给我指明正确的方向,但我仍在努力......请让我知道你如何解决这个小问题,如果可能的话。
几点。
1)您要搜索的是“一次性模式”。执行时要非常小心正确地。当然,互斥体already实现了一次性模式,所以我不清楚为什么你想要自己制作,但仍然值得学习。
请参阅此问题,了解有关像 RAII 一样使用一次性模式是否明智的一些其他想法:
使用 IDisposable 和“使用”作为获取“范围行为”以实现异常安全的手段是否滥用? https://stackoverflow.com/questions/2101524
2)Try-finally也有你想要的语义。当然,“using”块只是 try-finally 的语法糖。
3) 你是吗sure当有东西抛出时你想释放互斥体吗?您确定要扔进保护区吗?
由于以下原因,这是一种不好的代码味道。
首先为什么要有互斥体?通常是因为模式是这样的:
- 状态一致但陈旧
- 锁定对状态的访问
- 使状态不一致
- 使状态一致
- 解锁对国家的访问
- 状态现在一致且新鲜
考虑一下在“使状态一致”之前抛出异常时会发生什么。您解锁了对状态的访问,该状态现在不一致且陈旧.
这可能是一个更好的主意保持锁定。是的,这意味着存在死锁的风险,但至少你的程序不会在垃圾、陈旧、不一致的状态下运行。
从锁保护区域内抛出异常是一件非常非常可怕的事情,您应该尽可能避免这样做。从锁内部抛出的异常使您必须在两种可怕的事情之间做出选择:要么陷入死锁,要么当程序操作不一致的状态时出现疯狂的崩溃和不可重现的行为。
您真正应该实现的模式是:
- 状态一致但陈旧
- 锁定对状态的访问
- 使状态不一致
- 使状态一致
- 如果发生异常,则回滚到陈旧的一致状态
- 解锁对国家的访问
- 状态现在是一致的,如果没有例外,状态是新鲜的
这是更安全的选择,但是编写执行此类事务的代码很困难。没有人说多线程很容易。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)