C#ReaderWriterLockSlim避免递归的最佳实践

时间:2012-03-28 08:55:20

标签: c# thread-safety readerwriterlockslim

我有一个使用带有读取方法的ReaderWriterLockSlim的类和一个使用read方法来检索要修改的元素的write方法。一个简单的例子是:

class FooLocker
{
    ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
    List<Foo> fooList = new List<Foo>();

    public void ChangeFoo(int index, string bar)
    {
        locker.EnterWriteLock();

        try
        {
            Foo foo = GetFoo(index);
            foo.Bar = bar;
        }
        finally
        {
            locker.ExitWriteLock();
        }
    }

    public Foo GetFoo(int index) 
    {
        locker.EnterReadLock(); //throws System.Threading.LockRecursionException

        try
        {
            return fooList[index];
        }
        finally
        {
            locker.ExitReadLock();
        }
    }

    //snipped code for adding instances etc.
}

如上所述,此代码在调用LockRecursionException时抛出ChangeFoo(),因为当GetFoo()尝试输入读锁定时,已经保持写锁定。

我查看了ReaderWriterLockSlim的文档,我可以使用LockRecursionPolicy.SupportsRecursion来完成上述工作。但是,文档还建议不要将其用于任何新开发,只应在升级现有代码时使用。

鉴于此,如果write方法可以使用只读方法来检索需要修改的内容,那么实现相同结果的最佳实践是什么?

1 个答案:

答案 0 :(得分:24)

您可以将您的课程分为暴露方法和私人内部方法。内部方法执行像抓取一样的逻辑,公共方法执行锁定。例如:

class FooLocker 
{ 
    ReaderWriterLockSlim locker = new ReaderWriterLockSlim(); 
    List<Foo> fooList = new List<Foo>(); 


    public void ChangeFoo(int index, string bar) 
    { 
        locker.EnterWriteLock(); 

        try 
        { 
            Foo foo = UnsafeGetFoo(index); 
            foo.Bar = bar; 
        } 
        finally 
        { 
            locker.ExitWriteLock(); 
        } 
    } 

    public Foo GetFoo(int index)  
    { 
        locker.EnterReadLock();  

        try 
        { 
            return UnsafeGetFoo(index);
        } 
        finally 
        { 
            locker.ExitReadLock(); 
        } 
    } 

    private Foo UnsafeGetFoo(int index)
    {
        return fooList[index]; 
    }
}