C# 锁坏了?魔术僵局?

C# 锁坏了?魔术僵局?,c#,.net,multithreading,locking,C#,.net,Multithreading,Locking,我和multethreading bug一起工作。现在我看到,出于某种原因,lock甚至没有执行一次,而是被锁定了。我有下一节课: public sealed class Foo { private readonly object _lock = new object(); private static ulong _inCnt = 0; public void SomeMethod(ulong poo) { lock (_lock)

我和multethreading bug一起工作。现在我看到,出于某种原因,lock甚至没有执行一次,而是被锁定了。我有下一节课:

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(\u lock)
被释放
(\u inCnt=0)
。 我恢复了线程,等待了一会儿,暂停了线程并看到了相同的图片,相同(并且只有一个)线程仍在等待
SomeMethod中的
锁(\u lock)
,并且
\inCnt
为零!
但是如果锁被输入,则将是一个或多个(
\u inCnt++
lock(\u lock)
之后的第一行,不会发生异常,我们不会中止线程)。它如何是零和锁被锁定?< /p> 如果所有假设都是正确的,并且你是<强>真的< /强>确保没有意外的线程中止,那么你必须考虑GC堆数据损坏。存储锁定状态的System.Object中的字段相当脆弱,它是对象中的第一个字段。因此,即使pinvoked本机代码中存在适度的缓冲区溢出,也可能会覆盖该字段,并使CLR认为锁已被持有

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

三种基本情况:

  • 如果您在Threads窗口中找到了线程,那么就出现了死锁,您将对该线程正在执行的操作非常感兴趣。双击它并查看调用堆栈窗口,查看它为什么没有进展
  • 如果您找不到该线程,那么您会得到一个非常强烈的提示,您的代码正遭受“意外线程中止”的灾难
  • 如果您看到一个奇怪的随机数,那么您就看到了GC堆损坏场景

演示如何使用
Foo
类。我怀疑是Abort、OOMException或stackoverflowxception。除此之外,也许其他线程可以减少计数器?发布一个最小的复制,这样我们就可以研究它。你能为我们创建一个游戏吗?很难复制。。如果我不能提供足够的信息,我将尝试创建SSCCE。但是很奇怪,
\u inCnt
是静态的,而
\u lock
不是。