/ / Udostępnianie danych podczas wielowątkowości - czy zmienne niestatyczne są w porządku? - .net, wielowątkowość, statyczny, wspólny

Udostępnianie danych podczas wielowątkowości - czy zmienne niestatyczne są prawidłowe? - .net, wielowątkowość, statyczne, udostępnione

W dobrze znanym Artykuł Josepha Albahari na temat gwintowania, wszystkie zmienne klas używane przez wiele wątków są deklarowane jako static pola => wszystkie wątki mają dostęp do tej samej zmiennej. To musi być wyposażony przez lock() mechanizm we wszystkich miejscach czytania / pisania i praca jest wykonywana.

Moje pytanie dotyczy implementacji właściwości klasy. Rozumiem, że jest to ważne, jeśli zaimplementuję (na przykład) właściwość Timeout za pomocą static zaplecze sklepu:

class MyClassWithWorkerThread {
private readonly object _locker = new object();
private static int _Timeout = false;
private int Timeout {
get {
lock (_locker) {
return _Timeout;
}
}
set {
lock (_locker) {
_Timeout = value;
}
}
}
}

To zmieni zmienną _Timeout wspólne dla wszystkich instancji klasy.

Ale w moim przypadku przetwarzanie wielu wątków jest prywatne dla instancji klasy. Zaczyna się od New() i kończy się na Dispose(). Dostęp do głównego i roboczego wątku Timeout właściwość (ale _Timeout backing store nigdy nie jest dostępny poza getter / setter właściwości).

nie chcę _Timeout wartość do zastosowania. Chcę to mieć unikalny dla każdej instancji klasy. Moje pytanie brzmi: czy mogę bezpiecznie usunąć static od _Timeout zmienna, aby to osiągnąć?

Uwaga: przykro mi, jeśli w kodzie są jakieś błędy, faktycznie używam VB.NET i przekonwertowałem go za pomocą narzędzia. Mam nadzieję, że główne pytanie jest nadal jasne.

Odpowiedzi:

3 dla odpowiedzi № 1

Absolutnie bezpieczne i dość zalecane (zmienne statyczne są bolesne przy testowaniu, nawet jeśli są potrzebne). Zakładając, że bezpieczny masz również na myśli ważny nie musisz zapominać, że:

this.Timeout = 0; // This is safe and valid
++this.Timeout; // This is safe but not valid

Bo ++ operator nie jest atomowy (dlatego mamy Interlocked klasa). Oczywiście to samo dotyczy tej sytuacji:

if (this.Timeout == 0)
Timeout = 10;

Ponieważ nawet jeśli każdy dostęp jest bezpieczny (Powiedziałbym, że czytanie nieruchomości jest zawsze bezpieczne, ale możesz odczytać starą wartość bez lock bariera) nie jest to operacja atomowa, a wartość może ulec zmianie po teście i przed nowym przypisaniem. Jeszcze bardziej skomplikowane?

if (this.Timeout == 0)
Timeout = Timeout * 2;

W takim przypadku za każdym razem, gdy czytasz Timeout możesz otrzymać inną wartość. Z tego powodu powiedziałem, że blokada we właściwości jest rzadko przydatna, chyba że jest to właściwość tylko do odczytu. Znacznie lepiej usunąć tę blokadę z właściwości get / set i zawinąć kod w instrukcję lock:

lock (_locker) {
if (this.Timeout == 0)
Timeout = Timeout * 2;
}

Zauważ też, że dla int _Timeout (Przyjmuję zadanie z false to tylko literówka) możesz po prostu usunąć blokadę i zrobić to volatile:

private volatile int _Timeout;

Oczywiście to nie rozwiąże innych opisanych problemów, ale może być użyteczne (i szybsze) dla właściwości tylko do odczytu (lub w ściśle kontrolowanych sytuacjach, volatile modyfikatory mogą być trudne i mają inne znaczenie w porównaniu z C i łatwo o tym zapomnieć dostęp są atomowe, ale nic więcej).


1 dla odpowiedzi nr 2

Statyczne słowo kluczowe jest ortogonalnym (tzn. Niezależnym lub niezwiązanym z) wątkiem.

Słowa kluczowego static należy używać tylko wtedy, gdy chcesz tylko jedno wystąpienie tej właściwości / field / class / method / etc.

W twojej sytuacji nie potrzebujesz statycznego ustawienia _Timeout, jeśli chcesz, aby ta wartość była unikalna dla instancji.

Nie przeczytałem artykułu, do którego linkujesz, ale myślę, że chyba go źle zrozumiałeś (lub autor źle zrozumiał użycie statycznego)