Jest tu wiele pytań. Rozważając je pojedynczo:
przypisanie odniesienia jest niepodzielne, więc dlaczego potrzebne jest Interlocked.Exchange (ref Object, Object)?
Przypisanie odniesienia jest atomowe. Interlocked.Exchange nie tylko odnosi się do przypisania. Odczytuje bieżącą wartość zmiennej, usuwa starą wartość i przypisuje nową wartość do zmiennej, wszystko jako operacja niepodzielna.
mój kolega powiedział, że na niektórych platformach nie ma gwarancji, że przypisanie referencji jest atomowe. Czy mój kolega miał rację?
Nie. Przypisanie referencji jest gwarantowane na wszystkich platformach .NET.
Mój kolega wywodzi się z fałszywych przesłanek. Czy to oznacza, że ich wnioski są błędne?
Niekoniecznie. Twój kolega może udzielać ci dobrych rad z niewłaściwych powodów. Być może jest jakiś inny powód, dla którego powinieneś używać Interlocked.Exchange. Programowanie bez blokad jest niesamowicie trudne, a w momencie, gdy odejdziesz od ugruntowanych praktyk popieranych przez ekspertów w tej dziedzinie, jesteś w chwastach i ryzykujesz najgorszymi warunkami wyścigu. Nie jestem ani ekspertem w tej dziedzinie, ani znawcą twojego kodu, więc nie mogę dokonać oceny w ten czy inny sposób.
generuje ostrzeżenie „odniesienie do zmiennego pola nie będzie traktowane jako zmienne”. Co mam o tym myśleć?
Powinieneś zrozumieć, dlaczego jest to ogólnie problem. Pozwoli to zrozumieć, dlaczego ostrzeżenie nie jest ważne w tym konkretnym przypadku.
Kompilator wyświetla to ostrzeżenie, ponieważ oznaczenie pola jako nietrwałego oznacza, że „to pole będzie aktualizowane w wielu wątkach - nie generuj żadnego kodu, który buforuje wartości tego pola i upewnij się, że każdy odczyt lub zapis to pole nie jest „przesuwane do przodu i do tyłu w czasie” przez niespójności pamięci podręcznej procesora. ”
(Zakładam, że już to wszystko rozumiesz. Jeśli nie masz szczegółowego zrozumienia znaczenia zmiennej „ulotna” i jej wpływu na semantykę pamięci podręcznej procesora, oznacza to, że nie rozumiesz, jak to działa i nie powinieneś używać zmiennych. Programy bez blokad są bardzo trudne do poprawienia; upewnij się, że program jest poprawny, ponieważ rozumiesz, jak to działa, a nie przypadkowo).
Teraz załóżmy, że tworzysz zmienną, która jest aliasem pola nietrwałego, przekazując odniesienie do tego pola. Wewnątrz wywoływanej metody kompilator nie ma żadnego powodu, aby wiedzieć, że odwołanie musi mieć zmienną semantykę! Kompilator wesoło wygeneruje kod dla metody, która nie implementuje reguł dla zmiennych niestabilnych, ale zmienna jest zmienną . To może całkowicie zrujnować twoją logikę bez zamków; założeniem jest zawsze, że dostęp do zmiennego pola jest zawsze możliwy przy użyciu semantyki nietrwałej. Nie ma sensu traktować go czasami jako niestabilnego, a nie innym razem; musisz zawsze być konsekwentny, w przeciwnym razie nie możesz zagwarantować spójności przy innych dostępach.
Dlatego kompilator ostrzega, kiedy to robisz, ponieważ prawdopodobnie całkowicie zepsuje twoją starannie opracowaną logikę bez blokad.
Oczywiście Interlocked.Exchange jest napisane tak, aby oczekiwać zmiennego pola i postępować właściwie. Dlatego ostrzeżenie jest mylące. Bardzo tego żałuję; co powinniśmy zrobić, to zaimplementować jakiś mechanizm, za pomocą którego autor metody takiej jak Interlocked.Exchange mógłby umieścić atrybut na metodzie mówiąc „ta metoda, która pobiera ref, wymusza zmienną semantykę na zmiennej, więc pomiń ostrzeżenie”. Być może w przyszłej wersji kompilatora zrobimy to.
var myresult = await Task.Factory.CreateNew(() => MyWork(exclusivelyLocalStuffOrValueTypeOrCopy));
.Albo twój kolega się myli, albo wie coś, czego nie ma w specyfikacji języka C #.
5.5 Atomowość zmiennych odniesień :
Możesz więc pisać do zmiennego odniesienia bez ryzyka uzyskania uszkodzonej wartości.
Powinieneś oczywiście uważać przy podejmowaniu decyzji, który wątek powinien pobierać nowe dane, aby zminimalizować ryzyko, że zrobi to więcej niż jeden wątek naraz.
źródło
Interlocked.Exchange <T>
Zmienia się i zwraca oryginalną wartość, jest bezużyteczna, ponieważ chcesz ją tylko zmienić i, jak powiedział Guffa, jest już atomowa.
O ile profiler nie udowodni, że jest wąskim gardłem w twojej aplikacji, powinieneś rozważyć odblokowanie blokad, łatwiej jest zrozumieć i udowodnić, że twój kod jest poprawny.
źródło
Iterlocked.Exchange()
jest nie tylko atomowa, ale także dba o widoczność pamięci:Problemy z synchronizacją i wieloma procesorami
Oznacza to, że oprócz atomowości zapewnia, że:
źródło