Aby zsynchronizować dostęp do moich usług, używam klasy ReaderWriterLockSlim. Używam następującego kodu, aby uzyskać dostęp do moich właściwości w sposób bezpieczny dla wątków.Uwaga firmy Microsoft do ReaderWriterLockSlim.IsReadLockHeld/IsWriteLockHeld i jej konsekwencje
public class SomeClass
{
public readonly ReaderWriterLockSlim SyncObj = new ReaderWriterLockSlim();
public string AProperty
{
get
{
if (SyncObj.IsReadLockHeld)
return ComplexGetterMethod();
SyncObj.EnterReadLock();
try
{
return ComplexGetterMethod();
}
finally
{
SyncObj.ExitReadLock();
}
}
set
{
if (SyncObj.IsWriteLockHeld)
ComplexSetterMethod(value);
else
{
SyncObj.EnterWriteLock();
ComplexSetterMethod(value);
SyncObj.ExitWriteLock();
}
}
}
// more properties here ...
private string ComplexGetterMethod()
{
// This method is not thread-safe and reads
// multiple values, calculates stuff, ect.
}
private void ComplexSetterMethod(string newValue)
{
// This method is not thread-safe and reads
// and writes multiple values.
}
}
// =====================================
public static SomeClass AClass = new SomeClass();
public void SomeMultiThreadFunction()
{
...
// access with locking from within the setter
AClass.AProperty = "new value";
...
// locking from outside of the class to increase performance
AClass.SyncObj.EnterWriteLock();
AClass.AProperty = "new value 2";
AClass.AnotherProperty = "...";
...
AClass.SyncObj.ExitWriteLock();
...
}
Aby uniknąć niepotrzebnych blokad ilekroć pobrać lub ustawić wiele właściwości raz opublikowałem ReaderWriterLockSlim
-przedmiot i zablokować je od zewnątrz klasy każdym razem mam zamiar pobrać lub ustawić kilka właściwości. Aby to osiągnąć, moje metody pobierające i ustawiające sprawdzają, czy blokada została uzyskana przy użyciu właściwości IsReadLockHeld
i właściwości IsWriteLockHeld
z ReaderWriterLockSlim
. Działa to dobrze i zwiększyło wydajność mojego kodu.
Jak na razie dobrze, ale kiedy ponownie przeczytać dokumentację o IsReadLockHeld
i IsWriteLockHeld
Zauważyłem formularz uwaga Microsoft:
Ta właściwość jest przeznaczony do stosowania u twierdzi, lub do innych celów debugowania . Nie używaj go do kontrolowania przepływu programu.
Moje pytanie brzmi: Czy istnieje powód, dlaczego nie powinno się używać IsReadLockHeld/IsWriteLockHeld
na ten cel? Czy coś jest nie tak z moim kodem? Wszystko działa zgodnie z oczekiwaniami i znacznie szybciej niż przy użyciu blokad rekursywnych (LockRecursionPolicy.SupportsRecursion
).
Aby to wyjaśnić: To jest minimalny przykład. Nie chcę wiedzieć, czy sam zamek jest konieczny, czy można go usunąć lub osiągnąć w inny sposób. Chcę tylko wiedzieć, dlaczego nie powinienem używać IsReadLockHeld
/IsWriteLockHeld
, aby kontrolować przepływ programu zgodnie z dokumentacją.
Czytnik ReaderWriteLockSlim niczego nie chroni, .NET obiecuje już, że aktualizacje odniesień do obiektów są atomowe. Jedynym łagodnym efektem ubocznym będzie to, że aktualizacje ustawiacza będą widoczne w innych wątkach. Znacznie taniej jest po prostu użyć MemoryBarrier(). Żadnych gwarancji bezpieczeństwa nici, na pewno lepiej usunąć całkowicie SyncObj, ponieważ daje tylko fałszywe poczucie bezpieczeństwa. –
@EricLippert: Dokumenty dla 'IsRead/WriteLockHeld' sugerują, że zwracają' true', gdy * bieżący wątek * trzyma blokadę. Jeśli 'IsRead/WriteLockHeld' zwraca wartość true, jak może zmienić się stan blokady w tym wątku bez jawnego wywoływania' ExitRead/WriteLock'? – Iridium
@Iridium: Wycofuję komentarz; Obecnie nie jestem pewien, dlaczego dokumentacja powoduje takie zastrzeżenie. Powiedział: najlepszą praktyką jest robienie tego, co mówi dokumentacja. –