Jeśli volatile jest bezużyteczne dla wątków, dlaczego operacje atomowe wymagają wskaźników do danych volatile?

Czytałem z wielu źródeł, że słowo kluczowe volatile nie pomaga w scenariuszach wielowątkowych . Jednak twierdzenie to jest stale kwestionowane przez funkcje operacji atomowych, które akceptują wskaźniki volatile.

Na przykład w systemie Mac OS X mamy rodzinę funkcji OSAtomic:
SInt32 OSIncrementAtomic(volatile SInt32 *address);
SInt32 OSDrecrementAtomic(volatile SInt32 *address);
SInt32 OSAddAtomic(SInt32 amount, volatile SInt32 *address);
// ...

I wydaje się, że jest podobne użycie słowa kluczowego volatile w systemie Windows dla operacji Interlocked:

LONG __cdecl InterlockedIncrement(__inout LONG volatile *Addend);
LONG __cdecl InterlockedDecrement(__inout LONG volatile *Addend);

Wydaje się również, że w C++11, typy atomowe mają metody z modyfikatorem volatile, co musi w jakiś sposób oznaczać, że słowo kluczowe volatile ma jakiś związek z atomicznością.

Co mi umyka? Dlaczego dostawcy systemu operacyjnego i projektanci bibliotek standardowych nalegają na użycie słowa kluczowego volatile do celów wątku, jeśli nie jest to użyteczne?
Author: Community, 2011-06-18

4 answers

Volatile nie jest bezużyteczny dla współdzielonego dostępu przez wiele wątków - po prostu niekoniecznie jest wystarczający:

    Nie zawsze dostarcza semantyki bariery pamięci, która może być wymagana;]} Nie zapewnia gwarancji dostępu atomowego (na przykład jeśli obiekt Lotny jest większy niż rozmiar natywnego słowa pamięci platformy)

Należy również zauważyć, że kwalifikator volatile na argumentach wskaźnika do API w twoim przykładzie naprawdę tylko naprawdę dodaje możliwość API do odbierania wskaźników do obiektów volatile bez reklamacji - nie wymaga, aby wskaźniki wskazywały na rzeczywiste obiekty volatile. Standard umożliwia automatyczną konwersję wskaźnika niekwalifikowanego na wskaźnik kwalifikowany. Automatyczne przejście w drugą stronę (kwalifikowany wskaźnik do niekwalifikowanego) nie jest przewidziane w standardzie (Kompilatory zazwyczaj na to zezwalają, ale wydają Ostrzeżenie).

Na przykład, jeśli InterlockedIncrement() były prototypowe as:

LONG __cdecl InterlockedIncrement(__inout LONG *Addend);  // not `volatile*`

API może nadal działać poprawnie wewnętrznie. Jednakże, jeśli użytkownik miał zmienny obeject, który chciał przekazać do API, cast byłby wymagany, aby zapobiec wystąpieniu ostrzeżenia przez kompilator.

Ponieważ (konieczne lub nie), te API są często używane z obiektami kwalifikowanymi volatile, dodanie kwalifikatora volatile do argumentu wskaźnika zapobiega generowaniu bezużytecznej diagnostyki, gdy API jest używane, i nic nie szkodzi, gdy API jest używane z wskaźnik do obiektu nieulotnego.

 22
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-18 18:48:05

Nagle przyszło mi do głowy, że po prostu źle zinterpretowałem znaczenie volatile*. Podobnie jak {[1] } oznacza, że punkt nie powinien się zmieniać, volatile* oznacza, że punkt nie powinien być buforowany w rejestrze. Jest to dodatkowe ograniczenie, które można dowolnie dodawać: tak bardzo, jak możesz rzucić char* na const char*, możesz rzucić int* na volatile int*.

Więc zastosowanie modyfikatora volatile do punktów po prostu zapewnia, że funkcje atomowe mogą być używane na już volatile zmiennych. Dla zmiennych nieulotnych, dodanie kwalifikatora jest bezpłatne. Moim błędem było interpretowanie obecności słowa kluczowego w prototypach jako zachęty do korzystania z niego, a nie jako wygody dla tych, którzy go używają.

 17
Author: zneak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-18 17:46:06

C++11 ma atomikę zarówno dlavolatile, jak i nie-volatile zmiennych.

Jeśli kompilator przyjmuje wskaźnik do volatile int, oznacza to, że można go użyć , nawet jeśli zmienna jest zmienna zmienna. Nie przeszkadza to w używaniu funkcji na danych innych niżvolatile.

 2
Author: Bo Persson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-18 19:18:04

Cóż, słowo kluczowe 'volatile' sprawia, że kompilator zawsze ładuje / przechowuje wartość zmiennej z / do pamięci za każdym razem, gdy zmienna pojawia się w kodzie.
Zapobiega to pewnym optymalizacjom, np. że wartość jest po prostu ładowana do rejestru raz, a następnie używana wiele razy.
Jest to przydatne, gdy masz wiele wątków, które mogą modyfikować "współdzielone" zmienne między wątkami. Musisz upewnić się, że zawsze ładujesz/przechowujesz wartość Z / do pamięci, aby sprawdzić jej wartość, która mogła zostać zmodyfikowana przez inny wątek. Gdyby nie użyto volatile, drugi wątek mógłby nie zapisać nowej wartości do pamięci (ale umieścić ją w rejestrze lub mogła nastąpić Inna optymalizacja), a pierwszy wątek nie zauważy żadnej zmiany wartości.

W Twoich przypadkach 'volatile sint32 *address' mówi kompilatorowi, że pamięć wskazywana przez adres może ulec zmianie przez dowolne źródło. Stąd potrzeba operacji atomowej.

 1
Author: iolo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-18 17:41:55