锁定损坏? 魔术僵局?

我使用multethreading bug。 现在我看到由于某种原因锁定甚至没有被执行但被锁定。 我有下一堂课:

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中的所有线程,检查了所有线程,看到SomeMethod只有一个线程,它正在等待释放lock (_lock) (_inCnt = 0) 。 我恢复线程,等待一段时间,暂停线程并看到相同的图片,同样(并且只有一个)线程仍在等待lock (_lock)lock (_lock)并且_inCnt为零! 但是如果锁定将会是一个或多个( _inCnt++lock (_lock)后的第一行lock (_lock)不会发生exception,我们不会中止线程)。 如何将其锁定为零并锁定?

如果您的所有假设都是正确的,并且您确实没有意外的线程中止,那么您必须考虑GC堆数据损坏。 System.Object中存储锁状态的字段相当容易受到攻击,它是对象中的第一个字段。 因此,即使在pinvoked本机代码中的适度缓冲区溢出也可能会覆盖该字段并使CLR认为锁定被保留。

然而,假设是不可思议的问题和无法回答的问题的母亲。 最好检查它们,它实际上是可调试的。 我假设32位代码执行。 使用Debug + QuickWatch并键入&_lock 。 这为您提供了对象引用的地址。 切换到Debug + Windows + Memory + Memory1并输入您获得的地址。 右键单击窗口并选择“4字节整数”。 您现在将看到对象的地址,它存储在GC堆中。 从该数字中减去4,然后在“地址”框中键入结果。 您现在可以看到存储锁定状态的字段。 如果未保持锁定为0,如果保持锁定,则它包含拥有锁定的线程的Thread.ManagedId。 您可以将它与Debug + Windows + Threads窗口相关联。

三个基本场景:

  • 如果您在Threads窗口中找到该线程然后您遇到了死锁,那么您将对该线程正在做什么非常感兴趣。 双击它并查看“调用堆栈”窗口以查看它没有取得进展的原因
  • 如果你找不到那个线程那么你有一个非常强烈的提示,你的代码遭受了“意外线程中止”的不幸事故
  • 如果您看到一个奇怪的随机数,那么您就会遇到GC堆损坏情况。