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

C#ReaderWriterLockSlim避免递归的最佳实践,c#,thread-safety,readerwriterlockslim,C#,Thread Safety,Readerwriterlockslim,我有一个使用read方法的类,还有一个使用read方法检索要修改的元素的write方法。一个简单的例子是: class FooLocker { ReaderWriterLockSlim locker = new ReaderWriterLockSlim(); List<Foo> fooList = new List<Foo>(); public void ChangeFoo(int index, string bar) {

我有一个使用read方法的类,还有一个使用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.
}
class傻瓜
{
ReaderWriterLockSlim locker=新的ReaderWriterLockSlim();
列表傻瓜=新列表();
公共void ChangeFoo(整数索引、字符串栏)
{
locker.EnterWriteLock();
尝试
{
Foo-Foo=GetFoo(索引);
foo.Bar=Bar;
}
最后
{
locker.ExitWriteLock();
}
}
公共Foo GetFoo(int索引)
{
locker.EnterReadLock();//抛出System.Threading.LockRecursionException
尝试
{
返回愚人[索引];
}
最后
{
locker.exitradlock();
}
}
//用于添加实例等的剪切代码。
}
如上所述,当调用
ChangeFoo()
时,此代码抛出一个
LockRecursionException
,因为当
GetFoo()
尝试输入读锁时,写锁已经被持有

我已经检查了
ReaderWriterLockSlim
的文档,我可以使用
LockRecursionPolicy.SupportsRecursion
来允许上述操作。但是,文档还建议,这不应用于任何新的开发,而应仅在升级现有代码时使用


鉴于此,如果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 = 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]; 
    }
} 
class傻瓜
{ 
ReaderWriterLockSlim locker=新的ReaderWriterLockSlim();
列表傻瓜=新列表();
公共void ChangeFoo(整数索引、字符串栏)
{ 
locker.EnterWriteLock();
尝试
{ 
Foo-Foo=UnsafeGetFoo(索引);
foo.Bar=Bar;
} 
最后
{ 
locker.ExitWriteLock();
} 
} 
公共Foo GetFoo(int索引)
{ 
locker.EnterReadLock();
尝试
{ 
返回UnsafeGetFoo(索引);
} 
最后
{ 
locker.exitradlock();
} 
} 
私有Foo UnsafeGetFoo(int索引)
{
返回愚人[索引];
}
} 

您是否尝试通过读取ReaderWriterLockSlim.isReadLockHold值来检查读取锁定是否被保持?设置支持诅咒在这里不会是世界末日,但政治的答案是更好的方法。回答得好,谢谢!只要确保私有的不安全方法有足够的文档,以确保在没有确保锁定到位的情况下没有人使用它。@AdamRodger文档和do
System.Diagnostics.Debug.Assert(locker.isreadlockhold | | locker.isupgradableReadlockhold)
我不明白有什么区别,您刚刚将try-to-a-method中的代码移动到了一个方法,这有什么关系?@shinzou,因为递归是由一个锁定的方法调用另一个锁定的方法进行的。这将输入锁的方法与要求(理想情况下是断言)已输入锁的方法分开,从而避免了这种情况。