2013-05-09 13 views
5

(Uwaga: już zadałem to pytanie, ale odpowiedź była specyficzna dla Javy, więc zadaję to samo pytanie dla C# i platformy .NET, NIE jest to duplikat.)Czy nieresetowalne są "bezpieczne" wątki w C#/.NET?

Używam ten schemat przez jakiś czas, ale dopiero niedawno pomyślałem, że może to nie być w porządku, aby to zrobić. Zasadniczo używam jakiś wariant tego wzoru:

public class SampleAsync 
{ 
    public SampleAsync() { } 

    private bool completed; 
    public void Start() 
    { 
     var worker = new BackgroundWorker(); 
     worker.DoWork += (sender, e) => { 
      //... do something on a different thread 
      completed = true; 
     }; 
     worker.RunWorkerAsync(); 
    } 

    public void Update() 
    { 
     if (!completed) return; 
     //... do something else 
    } 
} 

* Użytkownik jest odpowiedzialny za upewnienie Start nazywa się tylko raz. Update jest nazywany zawsze i wszędzie.

Zawsze zakładałem, że jest bezpieczny dla wątków w strukturze C#/.NET, ponieważ nawet jeśli nic nie jest ściśle zsynchronizowane, ustawiam tylko completed na true. Po zaobserwowaniu, że jest to true, nie zostanie zresetowany do false. Jest on inicjalizowany na false w konstruktorze, który jest z definicji bezpieczny w wątku (chyba, że ​​zrobisz coś głupiego w nim). Czy w ten sposób można bezpiecznie używać flag nieresetowalnych? (A jeśli tak, to nawet dostarczyć żadnych korzyści wydajności?)

Dzięki

+2

Potrzebujesz 'lotny'. – SLaks

+0

W języku C# i Java? Czy inaczej jest wątkowo bezpieczny? – aboveyou00

+1

"Kiedy zostanie zaobserwowane, że jest prawdziwe" jest to fragment, który może nigdy nie wystąpić, jeśli nie użyjesz 'volatile'. –

Odpowiedz

3

Twój kod jest bezpieczne wątek, bo bool to typ atomowy.

MSDN:

Odczytuje i zapisuje następujące typy danych są niepodzielne: bool, char, bajt, sbyte, krótkie, ushort, uint, int, float, i typy referencyjne. W dodatku dodaje, odczytuje i zapisuje typy wyliczeniowe z typem bazowym w , poprzednia lista jest również atomowa. Czyta i zapisuje inne typy, , w tym długie, ulong, podwójne i dziesiętne, jak również zdefiniowane przez użytkownika typy , nie mają gwarancji, że są atomowe. Poza funkcjami biblioteki zaprojektowanymi do tego celu, nie ma gwarancji atomowej read-modify-write, na przykład w przypadku inkrementacji lub dekrementacji.

Patrz: http://msdn.microsoft.com/en-us/library/aa691278(v=vs.71).aspx

Proszę zaznaczyć swoje pole z volatile:

private volatile bool completed; 

MSDN:

Lotna słów kluczowych wskazuje, że pole może być modyfikowane w programie przez coś takiego jak system operacyjny, sprzęt lub jednoczesnego wykonywania wątku.

Patrz: http://msdn.microsoft.com/en-us/library/x13ttww7(v=vs.71).aspx

+0

... ale wszystkie zakłady są wyłączone, jeśli wyraźnie wyrównasz pole używając '[FieldOffset]' lub '[StructLayout]'. Zobacz [to pytanie] (http://stackoverflow.com/q/15249626/146622). – Virtlink

+1

Czy to gwarantuje, że zapis do tego pola propaguje do innych wątków? Nie sądzę. Wartość może zostać zarejestrowana. – usr

+0

@usr: Co masz na myśli mówiąc "propaguje do innych wątków"? –

3

Jest to w dużym stopniu zależy od architektury docelowej. Procesory Intela mają mocny model pamięci, więc masz tendencję do ucieczki z takim kodem. Ale wtedy jitter może cię zepsuć. Jitter x86 na przykład jest skłonny do przechowywania zmiennej w rejestrze procesora, szczególnie gdy instrukcja if() pojawia się w ciasnej pętli. I robi to tylko w wersji Release, niesamowitym koszmarze z debugowaniem. Zadeklarowanie zmiennej o zmiennej wartości: jest pomocniczą opcją. Jitter x64 nie potrzebuje tego, przynajmniej w obecnej wersji.Ale band-aidy nie powstrzymują krwawienia procesorów słabym modelem pamięci, takim jak ARM i Itanium. Z pewnością nie obiecują, że zaktualizowany stan zmiennej jest widoczny w innym wątku w najbliższym czasie. Program planujący wątek ma tendencję do przepłukiwania pamięci podręcznej cpu. Ostatecznie.

Nie ma sensu nie robić tego poprawnie. Użyj odpowiedniego obiektu synchronizacji, takiego jak AutoResetEvent. Lub Interlocked.CompareExchange(), jeśli obawiasz się o cykle.

+0

Czy lotna gwarancja, że ​​pole jest bezpośrednio przechowywane i zawsze ponownie ładowane z pamięci? (Aby to działało, wymagane są obie właściwości). Nie mam pojęcia, jakie gwarancje daje loteria. – usr

+0

@usr: Potrzebujesz również innej własności - że nie jest napisana wcześnie lub spekulacyjnie. –

+2

+1 Twój ostatni akapit podsumowuje to doskonale. Nie powinieneś pytać, czy coś jest bezpieczne dla wątków. Użyj obiektu synchronizacji i * wiem *. –

Powiązane problemy