【问题标题】:Exception on Monitor.Exit in C#C# 中的 Monitor.Exit 异常
【发布时间】:2018-04-01 21:28:19
【问题描述】:

这是一个我正在修复的大型多线程项目(不是我写的)。该应用程序挂在我正在追踪的一些锁上。

我检查并用Monitor.TryEnter 替换了所有“锁定”语句,这样我就可以设置等待期。我偶尔会遇到Monitor.Exit 的异常。

原来的样式是

private List<myClass> _myVar= new List<myClass>();

if (_myVar != null)
{
    lock (_myVar)
    {
        _myVar = newMyVar; // Where newMyVar is another List<myClass>
    }
}

我把上面所有的锁都换成了:

if (_myVar != null)
{
    bool lockTaken = false;
    try
    {
        Monitor.TryEnter(_myVar, new TimeSpan(0, 0, 5), ref lockTaken);
        if (lockTaken)
        {
            _myVar = newMyVar; // Where newMyVar is another List<myClass>
        }
    }
    finally
    {
        if (lockTaken) Monitor.Exit(_myVar);
    }
}

我得到的例外是

SynchronizationLockException 对象同步方法被调用 来自不同步的代码块

。如果是这样,为什么原来的lock语句也不抛出异常?

Monitor.Exit 放在try catch 中是否安全,如果出现异常则忽略它?

【问题讨论】:

  • 你有没有机会在你的新定制锁里做任何awaiting?
  • 你确定这是一个正在抛出而不是说脉冲的出口吗?
  • 你的问题有点不清楚。将所有锁更改为超时锁是为了尝试诊断 问题还是修复 问题?无论哪种方式,这都是一个有问题的技术,但是当你不清楚你在做什么时,很难给你建议。
  • 啊,你的编辑让一切变得不同。 原始代码完全错误。它永远不会可靠地工作。想象一下,你走进浴室,锁上门,当你在里面时建造第二扇门并保持打开状态,然后你想知道为什么有时会有两个人在里面洗手间。 永远不要在锁中锁定您正在修改的变量。这是一件完全疯狂和错误的事情。
  • 写这个“大型多线程程序”的人连关于锁的最基本知识都不懂,结果可能是一团糟。无法立即看出问题所在这一事实意味着您对锁的了解不够充分,无法正确修复它。

标签: c# synchronization


【解决方案1】:

应该很清楚为什么在新代码中出现异常。 如果锁定,则解锁的对象不是被锁定的对象。锁采用对象,而不是变量大错特错原代码的正确翻译是

// THIS CODE IS COMPLETELY WRONG; DO NOT USE IT
if (_myVar != null) 
{
    bool lockTaken = false;
    var locker = _myVar;
    try
    {
        Monitor.TryEnter(locker, new TimeSpan(0, 0, 5), ref lockTaken);
        if (lockTaken) 
        {
            _myVar = newMyVar; // where newMyVar is another List<myClass>
        }
    }
    finally
    {
        if (lockTaken) Monitor.Exit(locker);
    }
}

退出时不会抛出,但仍然是完全错误的

从不锁定变量的内容,然后改变变量每个后续的锁都会锁定一个不同的对象!所以你没有互斥。

并且从不锁定公共对象!如果该列表在任何地方泄漏,则其他错误代码可能会以意外的顺序锁定在该列表上,这意味着死锁——这是您诊断的原始症状。

对字段进行锁定的正确做法是创建一个私有的只读对象字段,用作储物柜,并每次访问该字段。这样您就知道(1)该字段总是在同一个锁下访问,无论其值如何,以及(2)锁对象仅用于锁定该字段,而不用于锁定其他内容。这样可以确保互斥并防止死锁。

有人写了一个大型多线程程序,却不了解关于锁的最基本事实,这意味着它几乎肯定是一堆难以发现的错误。这在阅读代码时并没有立即明显的事实意味着您没有足够的线程知识来正确解决问题。您将需要找到可以帮助您的这方面的专家,或者至少获得正确实践的最低工作知识。

我怎么强调这很难。 具有多个控制线程的程序很难在现代硬件上正确编写。您认为语言可以保证的许多事情只在单线程程序中得到保证。

【讨论】:

  • 感谢您的详尽回答。是的,我现在很快就获得了多线程方面的经验。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-17
  • 2014-12-18
  • 1970-01-01
  • 2011-07-06
  • 1970-01-01
相关资源
最近更新 更多