2012-03-28 7 views
10

Ich habe eine Klasse mit ReaderWriterLockSlim mit einer Lese- und einer Schreibmethode, die die read-Methode verwendet, um das zu ändernde Element abzurufen. Ein kurzes Beispiel wäre:C# ReaderWriterLockSlim Best Practice zur Vermeidung von Rekursionen

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

Wie oben, dieser Code ein LockRecursionException wirft, wenn ChangeFoo() Aufruf weil eine Schreibsperre bereits gehalten wird, wenn GetFoo() versucht eine Lesesperre einzugeben.

Ich habe die Dokumentation für ReaderWriterLockSlim überprüft und ich kann LockRecursionPolicy.SupportsRecursion verwenden, um das oben genannte zu ermöglichen. In der Dokumentation wird jedoch empfohlen, dass dies nicht für neue Entwicklungen verwendet wird und nur bei der Aktualisierung von vorhandenem Code verwendet werden sollte.

Gegeben, was ist die beste Vorgehensweise, um das gleiche Ergebnis zu erreichen, wo eine Schreibmethode eine schreibgeschützte Methode verwenden kann, um das zu ändern, was geändert werden muss?

+0

Haben Sie versucht, durch Lesen von ReaderWriterLockSlim.IsReadLockHeld Wert zu prüfen, ob die Lesesperre gehalten wird? http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.isreadlockheld.aspx –

+0

Setting SupportsRecursion wäre hier nicht das Ende der Welt, aber Polity's Antwort ist der bessere Ansatz. –

Antwort

17

Sie können Ihre Klasse in exponierte Methoden und private innere Methoden aufteilen. Die inneren Methoden erledigen die Logik wie das Holen und die öffentlichen Methoden führen das Sperren aus. Beispiel:

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

Große Antwort, danke! Stellen Sie nur sicher, dass die private unsichere Methode über ausreichende Dokumentation verfügt, um sicherzustellen, dass niemand sie verwendet, ohne sicherzustellen, dass die Sperre aktiviert ist. –

+1

@AdamRodger Dokument und tun 'System.Diagnostics.Debug.Assert (locker.IsReadLockHeld || locker.IsUpgradableReadLockHeld)' –

+0

Ich verstehe nicht, was ist der Unterschied, Sie haben nur den Code in den Versuch zu einer Methode bewegt, warum tut es Angelegenheit? – shinzou