Подтвердить что ты не робот

С# ReaderWriterLockSlim Лучшая практика, чтобы избежать рекурсии

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

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

4b9b3361

Ответ 1

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

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]; 
    }
}