【问题标题】:Can I put a return statement inside a lock我可以在锁内放一个 return 语句吗
【发布时间】:2010-11-24 10:57:26
【问题描述】:

骗子: return statement in a lock procedure: inside or outside

标题有点误导。我知道你可以做到,但我想知道性能影响。

考虑这两个代码块。 (无错误处理)

这个块在锁外有return

 public DownloadFile Dequeue()
 {
     DownloadFile toReturn = null;
     lock (QueueModifierLockObject)
     {
         toReturn = queue[0];
         queue.RemoveAt(0);
     }
     return toReturn;
 }

这个块有return语句

 public DownloadFile Dequeue()
 {
     lock (QueueModifierLockObject)
     {
         DownloadFile toReturn = queue[0];
         queue.RemoveAt(0);

         return toReturn;
     }
 }

代码有什么不同吗?我知道性能差异(如果有的话)会很小,但我特别想知道lock 的发布顺序是否会有所不同。

【问题讨论】:

  • 肯定这已经被覆盖了?
  • 我找不到结果,因为我之前没有使用正确的搜索词。是的,这是一个骗局。

标签: c# locking


【解决方案1】:

我相信 IL 会是相同的...我必须对其进行测试才能确定,但​​是 lock 语句会在 IL 中最终生成一个 try,并且返回会触发 finally(与发布)BEFORE堆栈框架关闭并返回给调用者,所以......

【讨论】:

    【解决方案2】:

    是的,但为什么不使用 Dequeue?

    记住 lock 基本上是以下内容的简写:

            try
            {
                Monitor.Enter(QueueModifierLockObject);
    
                DownloadFile toReturn = queue.Dequeue();         
    
                return toReturn;
            }
            finally
            {
                Monitor.Exit(QueueModifierLockObject);
            }
    

    【讨论】:

      【解决方案3】:

      C# 编译器会将 return 语句移到为 lock 语句创建的 try/finally 之外。就编译器将为它们发出的 IL 而言,您的两个示例都是相同的。

      这里有一个简单的例子证明:

      class Example
      {
          static Object obj = new Object();
      
          static int Foo()
          {
              lock (obj)
              {
                  Console.WriteLine("Foo");
                  return 1;
              }
          }
      
          static int Bar()
          {
              lock (obj)
              {
                  Console.WriteLine("Bar");
              }
              return 2;
          }
      }
      

      上面的代码被编译成如下:

      internal class Example
      {
              private static object obj;
      
              static Example()
              {
                      obj = new object();
                      return;
              }
      
              public Example()
              {
                      base..ctor();
                      return;
              }
      
              private static int Bar()
              {
                      int CS$1$0000;
                      object CS$2$0001;
                      Monitor.Enter(CS$2$0001 = obj);
              Label_000E:
                      try
                      {
                              Console.WriteLine("Bar");
                              goto Label_0025;
                      }
                      finally
                      {
                      Label_001D:
                              Monitor.Exit(CS$2$0001);
                      }
              Label_0025:
                      CS$1$0000 = 2;
              Label_002A:
                      return CS$1$0000;
              }
      
              private static int Foo()
              {
                      int CS$1$0000;
                      object CS$2$0001;
                      Monitor.Enter(CS$2$0001 = obj);
              Label_000E:
                      try
                      {
                              Console.WriteLine("Foo");
                              CS$1$0000 = 1;
                              goto Label_0026;
                      }
                      finally
                      {
                      Label_001E:
                              Monitor.Exit(CS$2$0001);
                      }
              Label_0026:
                      return CS$1$0000;
              }
      }
      

      如您所见,编译器已将Foo 中的return 语句移到try/finally 之外。

      【讨论】:

      • 确实如此。如果您查看生成的 IL,您就会明白我们为什么要这样做。您只能使用特殊的“离开”指令离开受保护区域,该指令知道如何清理异常处理粘液(或者,当然,通过抛出异常)。您不能在受保护区域之外进行普通分支或返回。因此,我们必须从受保护区域生成叶子到区域外生成的返回。
      猜你喜欢
      • 2013-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-16
      • 2018-07-01
      • 2023-03-04
      • 2011-05-19
      • 1970-01-01
      相关资源
      最近更新 更多