【问题标题】:Best practices for not the leave opened locks不打开锁的最佳实践
【发布时间】:2014-04-26 02:02:39
【问题描述】:

Albahari Threading section about ReaderWriterLockSlim 显示了此储物柜的使用情况。但是没有任何 try-catch 和 finally 阻止例外情况。

为什么他没有使用异常处理来保持打开的锁?在下面的示例中,如果 DivideBy 参数为 0,则写锁保持打开状态。

所以他尝试简单地显示用法而不是使示例变得复杂?如果是这样,处理这个问题的最佳做法是什么?如果它被持有,我们应该总是使用 finally 块作为退出锁吗?

public class Divide
{
    static int x = 1000;

    static ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

    public void DivideBy(int divide)
    {
        locker.EnterWriteLock();
        x = x / divide;
        locker.ExitWriteLock();
    }
}

【问题讨论】:

  • 我假设如果在锁内抛出异常,那么随着错误在调用堆栈中上升,锁被释放
  • @Jonesy 让我们从传入的答案中查看哪个是正确的。我也想知道这个。
  • 你为什么不试试呢?
  • 我实际上已经过测试,但线程是复杂的主题。我的测试表明它保持打开状态,但我目前仍不确定 %100。
  • 为什么不按照前面的评论提到的MSDN example...try/finally。

标签: c# .net multithreading thread-safety readerwriterlockslim


【解决方案1】:

这是我处理此问题的个人模式。我更喜欢使用using(IDisposable),因为我发现单个 using 块与 try finally 块相比,出错的范围要小得多。

public class Divide
{
    static int x = 1000;

    static ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

    public void DivideBy(int divide)
    {
        using(locker.DisposableWriteLock())
        {
            x = x / divide;     
        }
    }
}

public static class ReaderWriterLockSlimHelper
{
    public static IDisposable DisposableWriteLock(this ReaderWriterLockSlim readWriteLock)
    {
        readWriteLock.EnterWriteLock();
        return new LockContext(readWriteLock.ExitWriteLock);
    }

    private class LockContext : IDisposable
    {
        private Action _disposeContext;
        private bool _isDiposed;

        public LockContext(Action diposeContext)
        {
            _disposeContext = disposeContext;
        }

        public void Dispose()
        {
            if(_isDiposed)
                return;
            _disposeContext();
            _isDiposed = true;
        }
    }
}

【讨论】:

  • 很好,我也想过类似的方法。您在生产中使用此代码吗?你是否也写了 ReadLock 的扩展方法?
  • 不使用 ReaderWriterLock,我通常使用 Rx Disposable 助手。
  • 另一个问题的相同解决方案stackoverflow.com/questions/170028/…
【解决方案2】:

典型的成语是使用try...finally:

public void DivideBy(int divide)
{
    locker.EnterWriteLock();
    try
    {
        x = x / divide;
    }
    finally
    {
        locker.ExitWriteLock();
    }
}

这将确保在发生异常时释放锁。但是,请注意 Eric Lippert 的Locks and exceptions do not mix。您应该尽量使您的锁体(即您在持有锁时所做的任何事情)尽可能短而简单,以减少抛出异常的机会。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    • 2016-01-25
    • 1970-01-01
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多