2011-06-21 12 views
11

Mam klasę, która jest zaprojektowana przede wszystkim jako klasa POCO, z różnymi wątkami i zadaniami może odczytać jej wartości, a tylko inne tylko sporadycznie aktualizując te wartości. Wydaje się to być idealnym scenariuszem dla ReaderWriterLockSlim.Czy blokowanie dostępu do żądanego bool jest wymagane lub czy to przesada

Pytanie, czy w klasie właściwość, która musi być zabezpieczona wątkiem, czy nieruchomość jest boolem, to ta przesada? co się dzieje, jeśli jest to int? DateTime?

public class MyClass 
{ 
    private bool _theValue = false; 
    private ReaderWriterLockSlim _theValueLock = new ReaderWriterLockSlim(); 

    public bool TheValue 
    { 
    get 
    { 
     bool returnVal = false; 
     try 
     { 
     _theValueLock.EnterReadLock(); 
     returnVal = _theValue; 
     } 
     finally 
     { _theValueLock.ExitReadLock(); } 
     return returnVal; 
    } 
    set 
    { 
     try 
     { 
     _theValueLock.EnterWriteLock(); 
     _theValue = value; 
     } 
     finally 
     { _theValueLock.ExitWriteLock(); } 
    } 
    } 
} 

Czy cały ten kod przesadą i prosty ...

public bool TheValue { get; set; } 

... byłaby wystarczająca? Ponieważ typ to bool, czy jest bezpieczny? jeśli tak, to kiedy to nie jest bezpieczne? bajt? int? DateTime?

edytuj
Moja podstawowa architektura to mieć ten stan sklepu klasowego. Może mieć jedną usługę odpowiedzialną za robienie zapisów na tę klasę. Wszystkie pozostałe klasy mogą czytać i wykonywać swoją logikę na podstawie tych danych stanu. Zrobię co w mojej mocy, aby upewnić się, że wszystkie dane są spójne, ale, jak stwierdzono poniżej, moim głównym zmartwieniem była atomowość i splinching danych.

Wniosek
Dziękuję wszystkim za odpowiedź, wszystkie były cenne. Moim głównym zmartwieniem była niepodzielność zapisów/odczytów (tj. Martwienie się o splinching). W przypadku platformy .NET, jeśli dana zmienna jest wbudowanym typem wartości, który ma mniej niż 4 bajty, to odczyt i zapis są atomowe (np. Krótkie i int są dobre, długie i podwójne nie są).

+1

Nie ochrona jest bardzo ciężka pod zabiciem. Nie można uzyskać dokładnej odpowiedzi, nie pokazując, w jaki sposób usługa jest używana. Blokowanie na poziomie nieruchomości bardzo rzadko działa. –

+1

więcej dla własnego użytku niektóre linki [link] (http://www.albahari.com/threading/) najlepsze praktyki dotyczące wątków, [link] (http://blogs.msdn.com/b/ericlippert/archive/ 2011/05/26/atomicity-volatility-and-immutability-are-different-part-one.aspx) atmoicity, voltile dzięki @brian, [link] (http://blogs.msdn.com/b/brada/ archiwum/2003/04/03/49896.aspx) szybka lektura na temat atomowości dzięki @reed – Andre

+0

Jako osobistą notatkę, słuchając komentarzy dnr.tv i jon skeet na temat blokowania booli, przejrzałem ten http://askjonskeet.com/answer/6873994/Boolean-Property-Getter-and-Setter-Locking, który zasadniczo mówi, że w scenariuszach wielowątkowych dobrze jest go zablokować. – Andre

Odpowiedz

3

Masz kilka opcji.

  • Nic nie rób.
  • Uczyń klasę niezmienną.
  • Użyj zwykłego starego lock.
  • Oznacz pola jako volatile.
  • Użyj zestawu metod Interlocked.

Ponieważ odczyty i zapisy do bool gwarantują, że są atomowe, możesz nie robić nic. Będzie to w dużej mierze zależeć od sposobu, w jaki będzie używana twoja klasa. Atomowość nie jest równa bezpieczeństwu gwintów. To tylko jeden aspekt tego.

Idealnym rozwiązaniem jest uczynienie klasy niezmienną. Klasy niezmienne są na ogół bezpieczne dla wątków, ponieważ nie mogą być modyfikowane przez inne wątki (lub w ogóle o to chodzi). Czasami to po prostu nie jest możliwe.

Moje następne preferencje na liście to zwykły stary lock. Koszty związane z pozyskiwaniem i zwalnianiem są bardzo minimalne. W rzeczywistości wydaje mi się, że w większości sytuacji lock pobije ReaderWriterLockSlim, szczególnie jeśli wszystko, co robisz, to odczytanie/zapisanie zmiennej. Moje osobiste testy wskazują, że narzut na RWLS wynosi około 5x wolniej niż lock. Więc jeśli operacja odczytu nie jest wyjątkowo długa i znacznie przewyższa liczbę operacji zapisu, to RWLS nie pomoże.

Jeśli obawiasz się o obciążenie zamka, we wszystkich przypadkach oznacz pola jako volatile. Pamiętaj tylko, że volatile nie jest magiczną kulą, która rozwiązuje wszystkie problemy z współbieżnością. Nie jest to zamiennikiem dla lock.

8

W zależności od tego, w jaki sposób jest używany, może być konieczne oznaczenie wartości boolean volatile. Będzie to wymagało pola wsparcia dla Twojej nieruchomości.

Nie należy trzeba obsłużyć to z ReaderWriterLockSlim jak robisz teraz, ponieważ jest to mniej niż 32bits (zakładając, że używasz autoLayout, szczegóły patrz this post lub w przeważającej szczegółowo, sekcja zatytułowana Atomowość pamięci Dostęp do w specyfikacji ECMA 335). Jeśli używasz typu większego, wymagana jest jakaś forma synchronizacji.

Polecam:

public class MyClass 
{ 
    private volatile bool _theValue = false; 
    public bool TheValue 
    { 
     get { return _theValue; } 
     set { _theValue = value; } 
    } 
} 
+1

Jak już zauważyłeś, dostęp do 'bool' jest już atomowy. Ale 'volatile' nie zapewni żadnej synchronizacji ani bezpieczeństwa wątków. – user7116

+1

@sletterlettervariables: Prawda, ale rozwiązanie OP polegające na blokowaniu pojedynczej właściwości jest użyteczne tylko dla zagwarantowania atomowości - Nie było również synchronizacji ani bezpieczeństwa wątków w oryginalnym rozwiązaniu. Jest to całkowicie dopuszczalny zamiennik * w tym przypadku *. –

+0

wystarczająco fair. Chociaż jego oryginalne rozwiązanie z zamkiem zapewniłoby bezpieczny dostęp do wątku za pomocą RWLS. – user7116

4

Brak typu jest naprawdę bezpieczny! Dokładniej, specyfikacje C# zapewniają, że odczytywanie lub przypisywanie typów struktur mniejszych niż 4 bajty lub odwołań jest atomowych. jeśli twój system operacyjny ma 64 bity, CLR działa nieco lepiej, zapewniając to samo dla struktur mniejszych niż 8 bajtów.

Ale wszystko, co jest bardziej skomplikowane niż przypisanie lub odczytanie wartości, może zostać przerwane przez inną konkurencyjną nitkę, jeśli nie jesteś ostrożny.

Nawet coś tak prostego jak to:

myBool = !myBool 

mogą otrzymać nieoczekiwany wynik, jeśli konkurują wątek zmodyfikować wartość myBool.

Używanie zamków jest zalecane, jeśli chcesz mieć pewność, że coś takiego się nie stanie.Używanie zmiennego słowa kluczowego jest zdecydowanie odradzane, chyba że wiesz dokładnie, co robisz. Sprawdź theseblogposts, aby uzyskać dodatkowe informacje.

Jednak w twoim przykładzie, w którym właściwość nie wykonuje niczego oprócz pojedynczego zapisu lub pojedynczego odczytu, blokowanie jest bezużyteczne. Ale nie byłoby, gdyby doszło do dodatkowego leczenia.

+1

Empetizing your example. W twoim przykładzie czytasz pisać w tym samym czasie, podczas gdy myBool = true to tylko zapis.Dlatego volatile to za mało dla myBool =! MyBool – liorafar

Powiązane problemy