代码之家  ›  专栏  ›  技术社区  ›  Khadaji

如果锁定的对象内部发生异常,该对象是否保持锁定状态?

  •  73
  • Khadaji  · 技术社区  · 16 年前

    在c#threading应用程序中,如果我要锁定一个对象,比如说一个队列,如果发生异常,对象会保持锁定吗?以下是伪代码:

    int ii;
    lock(MyQueue)
    {
       MyClass LclClass = (MyClass)MyQueue.Dequeue();
       try
       {
          ii = int.parse(LclClass.SomeString);
       }
       catch
       {
         MessageBox.Show("Error parsing string");
       }
    }
    

    据我所知,捕获后的代码不会执行——但我一直在想锁是否会被释放。

    6 回复  |  直到 12 年前
        1
  •  101
  •   Eric Lippert    13 年前

    我注意到没有人在回答这个老问题时提到 是的,C#中的lock语句具有“finally”语义;当控件正常或异常退出锁时,锁被释放。你们都说这是件好事,但这是件坏事!如果您有一个引发未处理异常的锁定区域,正确的做法是 在销毁更多用户数据之前立即终止患病进程 打开锁,继续前进 .

    这样看:假设你有一个浴室,门上有锁,外面有一排人在等着。浴室里的炸弹爆炸,炸死了里面的人。你的问题是“在这种情况下,锁是否会自动解锁,以便下一个人可以进入浴室?”是的,会。 一枚炸弹在那里爆炸,炸死了人!水管可能被破坏了,房子的结构不再完好,而且 那里可能还有另一颗炸弹 . 正确的做法是

    我的意思是,仔细考虑一下:如果您锁定了一个代码区域,以便从数据结构中读取而不在另一个线程上进行变异,并且该数据结构中的某个内容引发了异常, . 用户数据现在乱七八糟;你不会想的 尝试保存用户数据 此时,因为您正在保存 贪污的 数据终止这个过程。

    如果数据以前没有损坏,现在肯定是 防范 . 现在,等待读取该状态的代码将

    无论如何分割,锁中的异常都是 坏消息 . 正确的问题不是“如果发生异常,我的锁会被清除吗?”正确的问题是“我如何确保锁内永远不会有异常?如果有,那么我如何构造我的程序,以便将突变回滚到以前的良好状态?”

        2
  •  91
  •   Kjartan madhukar Jha    9 年前

    in li;
    if(int.TryParse(LclClass.SomeString, out li)) {
        // li is now assigned
    } else {
        // input string is dodgy
    }
    

    锁将被释放,原因有2个;第一 lock

    Monitor.Enter(lockObj);
    try {
      // ...
    } finally {
        Monitor.Exit(lockObj);
    }
    

    第二您捕获并不重新抛出内部异常,因此

    因此,除了最致命的灾难性不可恢复的异常外,它将在所有情况下发布。

        3
  •  43
  •   Marc Gravell    13 年前

    lock try finally ,与 Monitor.Exit(myLock) 最后,无论你如何退出,它都会被释放。作为旁注, catch(... e) {throw e;} e ; 最好不要抓住它 完全 ,或者:使用 throw; 而不是 throw e; 这是一个重发。

    {
        bool haveLock = false;
        try {
           Monitor.Enter(myLock, ref haveLock);
        } finally {
           if(haveLock) Monitor.Exit(myLock);
        }
    } 
    
        4
  •  14
  •   Community CDub    4 年前

    lock语句被编译为对Monitor.Enter的调用,然后是tryfinally块。在finally块中,调用Monitor.Exit。

    x86和x64的JIT代码生成可确保线程中止不会在监视器之间发生。Enter调用和紧随其后的try块之间发生。”

    摘自: This site

        5
  •  6
  •   Brian Rasmussen    16 年前

    只是对Marc出色的回答补充一点。

    像这样的情况正是这种现象存在的原因 lock 关键词。它帮助开发人员确保锁在 finally

    如果你被迫使用 Monitor.Enter / Exit Monitor.Exit 最后 阻塞以确保在异常情况下正确释放锁。

        6
  •  6
  •   Ry- Vincenzo Alcamo    13 年前

    您的锁将被正确释放。A. lock

    try {
        Monitor.Enter(myLock);
        // ...
    } finally {
        Monitor.Exit(myLock);
    }
    

    finally 无论您如何离开,块都保证执行 try