gpt4 book ai didi

c# - 需要击败 GC 并在对象超出范围后将其销毁

转载 作者:太空狗 更新时间:2023-10-29 23:53:46 24 4
gpt4 key购买 nike

我有几段代码需要使用互斥锁来保护。问题是代码看起来像这样:

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;
}

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

Google 尚未为我指出正确的方向,但我仍在努力...请让我知道您如何解决这个小问题,如果可能的话。

最佳答案

对偶点。

1) 您要搜索的是“一次性图案”。要非常小心地正确地实现它。当然,Mutex 已经 实现了一次性模式,所以我不清楚您为什么要自己制作,但了解一下还是有好处的。

有关将一次性模式用作 RAII 是否明智的一些其他想法,请参阅此问题:

Is it abusive to use IDisposable and "using" as a means for getting "scoped behavior" for exception safety?

2) Try-finally 也有你想要的语义。当然,“using” block 只是 try-finally 的语法糖。

3) 您确定在抛出异常时释放互斥量吗?您确定要扔到保护区内吗?

由于以下原因,这是一种不好的代码味道。

为什么首先要有互斥体?通常是因为模式是这样的:

  • 状态一致但陈旧
  • 锁定对状态的访问
  • 使状态不一致
  • 使状态一致
  • 解锁对状态的访问
  • 状态现在是一致且新鲜的

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

保留锁 可能是更好的主意。是的,这意味着有死锁的风险,但至少您的程序不会在垃圾、陈旧、不一致的状态下运行。

从锁定保护区域内抛出异常是一件非常可怕的事情,您应该尽可能避免这样做。从锁内部抛出的异常使您不得不在两种可怕的事情之间做出选择:要么陷入死锁,要么在程序操纵不一致状态时发生疯狂崩溃和不可重现的行为。

您真正应该实现的模式是:

  • 状态一致但陈旧
  • 锁定对状态的访问
  • 使状态不一致
  • 使状态一致
  • 如果发生异常,回滚到陈旧的一致状态
  • 解锁对状态的访问
  • 状态现在是一致的,如果没有异常,就是新鲜的

这是更安全的选择,但编写执行此类事务的代码很困难。没有人说多线程很容易。

关于c# - 需要击败 GC 并在对象超出范围后将其销毁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2201123/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com