【问题标题】:Can Monitor.Enter throw an exception?Monitor.Enter 可以抛出异常吗?
【发布时间】:2012-02-09 01:05:55
【问题描述】:

Monitor.Enter 可以抛出任何异常。我正在做代码审查,发现 Monitor.Enter 在 try 块之前。你看到in有什么问题吗?

Monitor.Enter(...)
try
{
    ...
}
finally
{
    Monitor.Exit(..)
}

【问题讨论】:

  • 在 try 块中包含 Enter() 是一个错误。当 Enter() 可能失败时,您将调用 Exit()。您只需要对 Enter() 调用之后、 进入try 块之前引发的异常感到痛心。这实际上是 x64 抖动中的一个错误:bluebytesoftware.com/blog/2007/01/30/… 也是新 4.0 Monitor.Enter(object, ref bool) 重载背后的动机。

标签: c# multithreading synchronization


【解决方案1】:

这是正确的模式,无论Enter() 是否抛出(可以抛出)。

只有在对Enter() 的调用成功后,您的代码才有责任调用Exit()

假设对Enter() 的调用失败。那么调用对应的Exit() 是完全不正确的,只会让事情变得更糟。所以Enter() 必须在try 块之外(之前)。

【讨论】:

    【解决方案2】:

    Hans Passant 的评论当然是正确的。如果Monitor.Enter 在获取锁之前抛出了,那么你确实想要 finally 运行。如果它抛出 after 获取锁并且 after 进入尝试,则释放锁。 (稍后会详细介绍。)但是如果在获取锁之后但进入尝试之前发生抛出,那么锁将永远不会被清除。

    This is a rare but possible situation.

    在 C# 4 中,我们更改了 lock 语句的代码生成,以便监视器输入在 try 中。这确保了如果在获取锁后发生异常,锁总是被释放。但是,请注意这可能仍然是错误的。如果在获取锁之后发生了某些事情,那么锁所保护的任何非原子突变都可能是半完成的,然后 finally 块解锁锁并允许访问不一致的状态!这里的根本问题是,你一开始就不应该把锁扔进锁里。

    更多讨论请见my article about the issue

    【讨论】:

    • 我很想得到一个更通用的机制,也适用于自定义 Enter/Leave 对。当前常用的using 语句与旧的lock 语句存在相同的问题。
    • @CodeInChaos:但不同之处在于,如果在错误的地方抛出异常并且分配的非托管资源没有及时清理,那么最糟糕的情况就是有人无法使用那个资源。当被锁定对象的状态不一致时清理的锁是正确性问题,而不是礼貌问题。
    • 一个通用的、安全的Enter/Leave 模式除了简单地释放不安全的资源之外还有应用程序。我已经看到using 用于自定义锁定、数据库事务等的语句......自定义锁定将从这样的功能中受益匪浅,最终使其既安全又方便。我个人认为,当前版本的lock 语句首先不应该存在,而是使用这样一个更通用的特性来表达。但现在改变这一点为时已晚。
    【解决方案3】:

    Monitor.Enter至少可以抛出以下异常

    • 参数的ArgumentNullException是null
    • 如果执行Enter 的线程调用了Interrupt 方法,则发生ThreadInterruptedException。

    【讨论】:

      【解决方案4】:

      如果它获得了锁,那么没有。

      Monitor.Entertry 块之间可能会引发异常。

      推荐的方法是新的Enter 方法,是.NET 4 中的新方法:

      public static void Enter( obj, ref bool lockTaken )
      

      【讨论】:

      • 它仍然会抛出ArgumentNullException
      • @BoltClock 如果由于某种原因未能获得锁,lockTaken 将为 false。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-13
      • 1970-01-01
      • 2013-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多