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

这是危险的锁定模式吗?

  •  4
  • Martin  · 技术社区  · 14 年前

    我有一个用C#写的枚举器,它看起来像这样:

    try
    {
        ReadWriteLock.EnterReadLock();
        yield return foo;
        yield return bar;
        yield return bash;
    }
    finally
    {
        if (ReadWriteLock.IsReadLockHeld)
            ReadWriteLock.ExitReadLock();
    }
    

    3 回复  |  直到 14 年前
        1
  •  7
  •   Community omersem    7 年前

    finally 块总是被执行的,除非有人从计算机上拔下插头( well and a few other exceptions

    public static IEnumerable<int> GetNumbers() {
        try
        {
            Console.WriteLine("Start");
            yield return 1;
            yield return 2;
            yield return 3;
        }
        finally
        {
            Console.WriteLine("Finish");
        }
    }
    

    ...

    foreach(int i in GetNumbers()) {
        Console.WriteLine(i);
        if(i == 2) break;
    }
    

    以上的输出将是

    起点
    1

    完成

    yield return ,不仅仅是 yield . 但我想那只是个打字错误。

        2
  •  3
  •   Community omersem    7 年前

    David's answered 您打算问的问题(关于枚举方面),但还有两点需要考虑:

    1. 如果 ReadWriteLock.EnterReadLock 引发了异常?
    2. 如果 ReadWriteLock.ExitReadLock 引发了异常?

    在#1,你会打电话给 ReadWriteLock.ExitReadLock 不恰当地。在#2中,可以隐藏已抛出的现有异常(自 finally 子句发生的原因可能是主线处理到达 try 因为抛出了异常;在后一种情况下,您可能不想掩盖例外情况)。也许这两种情况在这个特定的案例中都不太可能发生,但是您询问了 作为一种模式,它有这些问题。

        3
  •  2
  •   Andrey    14 年前

    最后将以任何方式执行,但锁定可能不安全。比较以下方法:

    class Program
    {
        static IEnumerable<int> meth1()
        {
            try
            {
                Console.WriteLine("Enter");
                yield return 1;
                yield return 2;
                yield return 3;
            }
            finally
            {
                Console.WriteLine("Exit");
            }
        }
    
        static IEnumerable<int> meth2()
        {
            try
            {
                Console.WriteLine("Enter");
                return new int[] { 1, 2, 3 };
            }
            finally
            {
                Console.WriteLine("Exit");
            }
        }
    
        static public void Main()
        {
            foreach (int i in meth1())
            {
                Console.WriteLine("In");
            }
            Console.WriteLine();
            foreach (int i in meth2())
            {
                Console.WriteLine("In");
            }   
        }
    }
    

    Enter
    In
    In
    In
    Exit
    
    Enter
    Exit
    In
    In
    In
    

    如果您的处理(每次迭代)需要花费很多时间,则先填充集合,然后处理,而不是生成,这样更为合理。