代码之家  ›  专栏  ›  技术社区  ›  Cédric Boivin

如何正确使用readerwriterlock

  •  2
  • Cédric Boivin  · 技术社区  · 17 年前

    您好,我需要在我的方法中使用writerreaderlock。我想知道如何正确使用它。

    我有一本ObjectA词典

    public class ObjectA
    {
        public ReaderWriterLock RWL {get;set;}
        public ObjectB obj {get;set;}
        public ObjectA()
        {
            RWL = new ReaderWriterLock();
        }
    }
    
    public class ObjectB
    {
        int TTL {get;set;}
        string Value {get;set;}
    }
    

    在我的方法中,我使用ObjectA字典,键是Guid,因此假设当我调用dict[Guid]时,它总是返回我的ObjectA实例(例如)

    public foo()
    {
        ObjecA objA = dict[guid];
        objA.RWL.AcquireReaderLock(500);
        if(objA.obj.TTL<=0)
        {
            objA.obj.RWL.AcquireWriterLock(1000);
            objA.obj.Value = DateTime.Now().ToString();
            objA.obj.RWL.ReleaseWriterLock();
        }else{
             int ttl = objA.obj.TTL;
             Interlocked.Decrement(ref ttl);
        }    
        objA.RWL.ReleaseReaderLock();
    }
    

    我真的不确定我在那里使用了读写器,我需要如何使用读写器锁和条件验证?

    1 回复  |  直到 15 年前
        1
  •  6
  •   Justin Grant    17 年前

    此代码存在许多问题,包括:

    • 实际上,您从来没有在类实例中递减TTL——正如Nikolai指出的,您递减的是局部变量! Interlocked.Decrement(ref objA.obj.TTL) 问题是如何正确地做到这一点。
    • 你应该使用 ReaderWriterLockSlim ,这是现在比老年人更喜欢的 ReaderWriterLock 班级。查看后一个超链接了解原因。
    • 在获取写锁时,如果已经有读锁,则需要升级锁——通常在lock类上有一个单独的方法来实现这一点。同样,升级后,释放锁需要一种方法来释放锁,而不是一种方法来释放写锁,另一种方法来释放以前的读锁。
    • 您需要处理无法获取锁的故障情况。
    • 您需要将代码封装在 using 或 try/finally 块以确保即使发生异常也释放资源。

    您是否真的需要使用读写器锁,而不是使用像 lock{} statement . 即使对于非常熟悉这些API和概念的开发人员来说,获得正确的读写器锁并避免死锁也是很困难的,即使如此,他们通常只在性能最关键的地方(每秒1000秒以上)使用它们。换句话说,您最好从一个更简单的方法开始,使用 锁{} ,只会退回使用 ReaderWriterLockSlim 如果性能不合格。

    作为起点,我建议您在问题中添加更多信息:

    • 首先,包括对您正在尝试做的事情的高级描述,包括对功能和性能的高级需求。这可以帮助我们推荐正确的解决方案,并了解读写器锁定是否是正确的方法。
    • 试着用伪代码或简单的英语写出您希望代码的行为,包括您希望如何解决上面的逻辑问题(例如,发生超时时该怎么做,TTL是如何设置的,等等)
    • 修改您的代码示例,以包括我上面提到的部分/所有问题的修复

    我向您保证,如果您在问题中包含此附加信息,您将得到更好的答案,这可以帮助您解决任何剩余的代码问题。:-)