C # ReaderWriterLockSlim Лучшая практика, чтобы избежать рекурсии - PullRequest
13 голосов
/ 28 марта 2012

У меня есть класс, использующий ReaderWriterLockSlim с методом чтения и методом записи, который использует метод чтения для извлечения изменяемого элемента.Быстрый пример:

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, чтобы вышеописанное работало.Однако в документации также рекомендуется, чтобы это не использовалось для какой-либо новой разработки и должно использоваться только при обновлении существующего кода.

Учитывая это, какова лучшая практика для достижения того же результата, что и метод записиможно использовать метод только для чтения, чтобы получить то, что нужно изменить?

1 Ответ

25 голосов
/ 28 марта 2012

Вы можете разделить свой класс на открытые методы и закрытые внутренние методы. Внутренние методы выполняют логику, подобную извлечению, а открытые методы выполняют блокировку. Пример:

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]; 
    }
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...