我正在处理多线程错误。现在我看到由于某种原因锁甚至没有执行一次而是被锁定了。我还有下一堂课:
public sealed class Foo
{
private readonly object _lock = new object();
private static ulong _inCnt = 0;
public void SomeMethod(ulong poo)
{
lock (_lock)
{
_inCnt++;
... [some code]
}
}
}
我暂停了VS中的所有线程,检查了所有线程,发现VS中只有一个线程SomeMethod
它正在等待lock (_lock)
被释放(_inCnt = 0)
。
我恢复了线程,等待了一段时间,暂停了线程并看到相同的图片,相同的(并且只有一个)线程仍在等待lock (_lock)
in SomeMethod
and _inCnt
为零!
但如果进入锁定状态,它将是一个或多个(_inCnt++
是之后的第一行lock (_lock)
不会发生任何异常,我们不会中止线程)。怎么会是零而lock被锁住了呢?
如果你所有的假设都是正确的,并且你是really确保从未发生过意外的线程中止,那么您必须考虑 GC 堆数据损坏。 System.Object 中存储锁定状态的字段相当容易受到攻击,它是对象中的第一个字段。因此,即使 pinvoked 本机代码中的适度缓冲区溢出也可能会覆盖该字段,并使 CLR 认为锁定已被持有。
然而,假设是无法解决的问题和无法回答的问题之母。最好检查一下,它实际上是可调试的。我假设 32 位代码执行。使用 Debug + QuickWatch 并输入&_lock
。这为您提供了对象引用的地址。切换到 Debug + Windows + Memory + Memory1 并输入您获得的地址。右键单击窗口并选择“4 字节整数”。现在您将看到对象的地址,它存储在 GC 堆中。将该数字减去 4,然后在“地址”框中键入结果。您现在可以看到存储锁定状态的字段。如果未持有锁,则为 0;如果持有锁,则它包含拥有该锁的线程的 Thread.ManagedId。您可以将其与“调试 + Windows + 线程”窗口相关联。
三个基本场景:
- 如果您在“线程”窗口中找到该线程,则说明您遇到了死锁,您将对该线程正在执行的操作非常感兴趣。双击它并查看“调用堆栈”窗口以了解为什么它没有取得进展
- 如果您找不到该线程,那么您有一个非常强烈的暗示,即您的代码正在遭受“意外的线程中止”灾难
- 如果您看到一个奇怪的随机数,那么您就遇到了 GC 堆损坏的情况。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)