2012-03-28 19 views
10

Tengo una clase que usa ReaderWriterLockSlim con un método de lectura y un método de escritura que utiliza el método de lectura para recuperar el elemento que se va a modificar. Un ejemplo rápido sería:C# ReaderWriterLockSlim Mejor práctica para evitar la recursión

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. 
} 

Como el anterior, este código produce un LockRecursionException al llamar ChangeFoo() debido a un bloqueo de escritura ya se lleva a cabo cuando GetFoo() intente entrar en un bloqueo de lectura.

He revisado la documentación para ReaderWriterLockSlim y puedo usar LockRecursionPolicy.SupportsRecursion para permitir que lo anterior funcione. Sin embargo, la documentación también recomienda que esto no se debe usar para ningún desarrollo nuevo y solo se debe usar al actualizar el código existente.

Dado esto, ¿cuál es la mejor práctica para lograr el mismo resultado donde un método de escritura puede usar un método de solo lectura para recuperar lo que necesita modificarse?

+0

¿Intentó comprobar si el bloqueo de lectura se mantiene leyendo el valor ReaderWriterLockSlim.IsReadLockHeld? http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.isreadlockheld.aspx –

+0

Configurando soportesRecursión no sería el fin del mundo aquí, pero el anwer de Polity es el mejor enfoque. –

Respuesta

17

Puede dividir su clase en métodos expuestos y métodos internos privados. Los métodos internos hacen la lógica como ir a buscar y los métodos públicos realizan el bloqueo. Ejemplo:

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(); //throws System.Threading.LockRecursionException 

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

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

¡Gran respuesta, gracias! Solo debe asegurarse de que el método privado no seguro tenga la documentación adecuada para asegurarse de que nadie lo use sin asegurarse de que el bloqueo esté en su lugar. –

+1

@AdamRodger document y hacer 'System.Diagnostics.Debug.Assert (Locker.IsReadLockHeld || locker.IsUpgradableReadLockHeld)' –

+0

No entiendo cuál es la diferencia, acaba de mover el código en el intento de un método, ¿por qué ¿importar? – shinzou

Cuestiones relacionadas