Dlaczego Lotny istnieje?

Do czego służy słowo kluczowe volatile? W C++ jaki problem rozwiązuje?

W moim przypadku nigdy świadomie tego nie potrzebowałem.
Author: Evan Teran, 2008-09-16

16 answers

volatile jest potrzebny, jeśli czytasz z miejsca w pamięci, że, powiedzmy, zupełnie oddzielny proces / urządzenie / cokolwiek może pisać.

Pracowałem z dwuportową pamięcią ram w systemie wieloprocesorowym w prostym C. użyliśmy sprzętowo zarządzanej 16-bitowej wartości jako semafora, aby wiedzieć, kiedy drugi facet został skończony. Zasadniczo zrobiliśmy to:

void waitForSemaphore()
{
   volatile uint16_t* semPtr = WELL_KNOWN_SEM_ADDR;/*well known address to my semaphore*/
   while ((*semPtr) != IS_OK_FOR_ME_TO_PROCEED);
}

Bez volatile, optymalizator widzi pętlę jako bezużyteczną (facet nigdy nie ustawia wartości! On jest szalony, pozbądź się tego kodu!) i mój kod by kontynuuj bez zdobycia semafora, powodując później problemy.

 220
Author: Doug T.,
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
2012-02-10 17:41:20

volatile jest potrzebny przy opracowywaniu systemów wbudowanych lub sterowników urządzeń, gdzie trzeba odczytać lub zapisać urządzenie sprzętowe zmapowane pamięcią. Zawartość określonego rejestru urządzeń może ulec zmianie w dowolnym momencie, więc potrzebujesz słowa kluczowego volatile, aby upewnić się, że takie dostępy nie są optymalizowane przez kompilator.

 69
Author: ChrisN,
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
2012-10-20 17:04:12

Większość nowoczesnych procesorów posiada rejestry zmiennoprzecinkowe, które mają ponad 64 bity precyzji. W ten sposób, jeśli wykonasz kilka operacji na liczbach o podwójnej precyzji, otrzymasz odpowiedź o wyższej precyzji niż w przypadku skrócenia każdego wyniku pośredniego do 64 bitów.

Jest to zwykle świetne, ale oznacza to, że w zależności od tego, jak kompilator przypisał rejestry i zrobił optymalizacje, będziesz miał różne wyniki dla dokładnie tych samych operacji na dokładnie tych samych wejściach. Jeśli potrzebujesz spójności, a następnie możesz wymusić powrót każdej operacji do pamięci za pomocą słowa kluczowego volatile.

Jest również przydatny dla niektórych algorytmów, które nie mają sensu algebraicznego, ale zmniejszają błąd zmiennoprzecinkowy, takich jak sumowanie Kahan. Algebraicznie jest to nop, więc często zostanie niepoprawnie zoptymalizowany, chyba że niektóre zmienne pośrednie są lotne.

 60
Author: tfinniga,
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
2016-02-04 12:35:11

Z artykułu dan Saks o systemach wbudowanych:

"obiekt zmienny to taki, którego wartość może ulec spontanicznej zmianie. Oznacza to, że kiedy deklarujesz obiekt jako zmienny, mówisz kompilatorowi, że obiekt może zmienić stan, nawet jeśli żadne instrukcje w programie nie wydają się go zmieniać."

Linki do 2 wspaniałych artykułów Pana Saksa dotyczących lotnych słowo kluczowe:

Http://www.embedded.com/columns/programmingpointers/174300478 http://www.embedded.com/columns/programmingpointers/175801310

 38
Author: MikeZ,
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
2008-09-16 14:32:59

Musisz używać volatile przy implementacji struktur danych bez blokady. W przeciwnym razie kompilator może zoptymalizować dostęp do zmiennej, co zmieni semantykę.

Mówiąc inaczej, volatile mówi kompilatorowi, że dostęp do tej zmiennej musi odpowiadać operacji odczytu/zapisu w pamięci fizycznej.

Na przykład, tak jest deklarowane InterlockedIncrement w API Win32:

LONG __cdecl InterlockedIncrement(
  __inout  LONG volatile *Addend
);
 22
Author: Frederik Slijkerman,
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
2008-09-17 11:55:18

Duża aplikacja, nad którą pracowałem we wczesnych latach 90. zawierała obsługę wyjątków w języku C przy użyciu setjmp i longjmp. Słowo kluczowe volatile było konieczne dla zmiennych, których wartości musiały być zachowane w bloku kodu, który służył jako klauzula "catch", aby te zmienne nie były przechowywane w rejestrach i usuwane przez longjmp.

 9
Author: ,
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
2008-09-16 21:03:12

W standardowym C, jednym z miejsc do użycia {[1] } jest obsługa sygnału. W rzeczywistości, w standardowym C, wszystko, co możesz bezpiecznie zrobić w obsłudze Sygnału, to zmodyfikować zmienną volatile sig_atomic_t lub szybko zakończyć działanie. Rzeczywiście, AFAIK, jest to jedyne miejsce w standardzie C, w którym użycie volatile jest wymagane, aby uniknąć niezdefiniowanego zachowania.

ISO / IEC 9899: 2011 §7.14.1.1 Funkcja signal

¶5 Jeśli sygnał występuje inaczej niż w wyniku wywołania funkcji abort lub raise, zachowanie jest niezdefiniowane, jeśli obsługa sygnału odnosi się do dowolnego obiektu ze statycznym lub wątkowym czas przechowywania, który nie jest blokowanym obiektem atomowym innym niż przypisanie wartości do obiekt zadeklarowany jako volatile sig_atomic_t, lub funkcja obsługi sygnału wywołuje dowolną funkcję w bibliotece standardowej innej niż funkcja abort, Funkcja _Exit, quick_exit funkcja, lub signal Funkcja z pierwszym argumentem równym numer sygnału odpowiadający sygnałowi, który spowodował wywołanie funkcji obsługi. Ponadto, jeśli takie wywołanie funkcji signal spowoduje powrót SIG_ERR, wartość {[13] } jest nieokreślona.252)

252) Jeśli jakikolwiek sygnał jest generowany przez asynchroniczną obsługę sygnału, zachowanie jest niezdefiniowane.

Oznacza to, że w standardzie C można napisać:

static volatile sig_atomic_t sig_num = 0;

static void sig_handler(int signum)
{
    signal(signum, sig_handler);
    sig_num = signum;
}
I niewiele więcej.

POSIX jest o wiele bardziej pobłażliwy w tym, co można zrobić w obsłudze sygnału, ale nadal istnieją ograniczenia (i jeden z ograniczenia polegają na tym, że standardowa biblioteka I/o - printf() et al-nie może być bezpiecznie używana).

 9
Author: Jonathan Leffler,
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-07-27 18:14:02

Używałem go w kompilacjach debugowania, gdy kompilator nalega na optymalizację zmiennej, którą chcę widzieć podczas przechodzenia przez kod.

 7
Author: indentation,
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
2008-09-16 21:09:49

Rozwijając się dla wbudowanego, mam pętlę, która sprawdza zmienną, którą można zmienić w obsłudze przerwań. Bez" volatile " pętla staje się noopem - o ile kompilator może stwierdzić, że zmienna nigdy się nie zmienia, więc optymalizuje kontrolę.

To samo dotyczy zmiennej, która może zostać zmieniona w innym wątku w bardziej tradycyjnym środowisku, ale tam często wykonujemy połączenia synchronizacyjne, więc kompilator nie jest tak wolny z optymalizacją.

 6
Author: Arkadiy,
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
2008-09-16 14:08:47
  1. musisz go używać do implementacji spinlocków, jak również niektórych (wszystkich?) lock-free data structures
  2. Użyj go z operacjami atomowymi / instrukcjami
  3. pomógł mi raz pokonać błąd kompilatora (błędnie wygenerowany kod podczas optymalizacji)
 5
Author: Mladen Janković,
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
2008-09-16 14:15:15

Poza używaniem go zgodnie z przeznaczeniem, Lotny jest używany w metaprogramowaniu (szablonowym). Może być używany do zapobiegania przypadkowemu przeciążeniu, ponieważ atrybut Lotny (jak const) bierze udział w rozwiązywaniu przeciążeń.

template <typename T> 
class Foo {
  std::enable_if_t<sizeof(T)==4, void> f(T& t) 
  { std::cout << 1 << t; }
  void f(T volatile& t) 
  { std::cout << 2 << const_cast<T&>(t); }

  void bar() { T t; f(t); }
};

Jest to legalne; oba przeciążenia są potencjalnie możliwe do wywołania i robią prawie to samo. Obsada w volatile overload jest legalna, ponieważ wiemy, że bar i tak nie przejdzie nieulotnej T. Wersja volatile jest jednak zdecydowanie gorsza, więc nigdy nie wybierana w rozdzielczości przeciążenia, jeśli nieulotny f jest dostępny.

Zauważ, że kod nigdy nie zależy od dostępu do pamięci volatile.

 5
Author: MSalters,
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
2018-02-06 16:06:14

Słowo kluczowe volatile ma na celu uniemożliwienie kompilatorowi stosowania optymalizacji na obiektach, które mogą się zmienić w sposób, który nie może być określony przez kompilator.

Obiekty zadeklarowane jako volatile są pomijane podczas optymalizacji, ponieważ ich wartości mogą być w dowolnym momencie zmieniane przez kod spoza zakresu bieżącego kodu. System zawsze odczytuje bieżącą wartość obiektu volatile z miejsca pamięci, zamiast przechowywać jego wartość w tymczasowym rejestrze w miejscu, w którym jest żądany, nawet jeśli poprzednia Instrukcja zapytała o wartość z tego samego obiektu.

Rozważmy następujące przypadki

1) zmienne globalne zmodyfikowane przez procedurę obsługi przerwań poza zakresem.

2) zmienne globalne w aplikacji wielowątkowej.

Jeśli nie użyjemy kwalifikatora lotnego, mogą pojawić się następujące problemy

1) kod może nie działać zgodnie z oczekiwaniami, gdy optymalizacja jest włączona.

2) Kod może nie działać zgodnie z oczekiwaniami, gdy przerwania są włączone i używane.

Volatile: a programmer ' s best friend

Https://en.wikipedia.org/wiki/Volatile_ (computer_programming)

 3
Author: roottraveller,
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
2016-10-12 07:10:42

Oprócz tego, że słowo kluczowe volatile jest używane do informowania kompilatora, aby nie optymalizował dostępu do jakiejś zmiennej( która może być modyfikowana przez wątek lub procedurę przerwania), może być również używane do usuwania niektórych błędów kompilatora -- tak może być - - -.

Na przykład pracowałem na wbudowanej platformie, gdzie kompilator robił błędne ustalenia dotyczące wartości zmiennej. Gdyby kod nie był zoptymalizowany program działałby ok. Z optymalizacjami (które były naprawdę potrzebne, ponieważ była to krytyczna rutyna) kod nie działał poprawnie. Jedynym rozwiązaniem (choć niezbyt poprawnym) było zadeklarowanie zmiennej "wadliwa" jako zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna

 1
Author: INS,
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
2008-09-16 21:02:04

Należy przypomnieć, że w funkcji obsługi sygnału, Jeśli chcesz uzyskać dostęp/zmodyfikować globalną zmienną (na przykład, oznaczyć ją jako exit = true), musisz zadeklarować tę zmienną jako 'volatile'.

 0
Author: bugs king,
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
2017-05-05 10:33:05

Twój program wydaje się działać nawet bez volatile słowa kluczowego? Być może to jest powód:

Jak wspomniano wcześniej słowo kluczowe volatile pomaga w takich przypadkach jak

volatile int* p = ...;  // point to some memory
while( *p!=0 ) {}  // loop until the memory becomes zero

Ale wydaje się, że nie ma prawie żadnego efektu po wywołaniu funkcji zewnętrznej lub nie-inline. Np.:

while( *p!=0 ) { g(); }

Następnie z volatile lub bez volatile generowany jest prawie taki sam wynik.

Tak długo, jak g() może być całkowicie inlined, kompilator może zobaczyć wszystko, co się dzieje i dlatego może zoptymalizować. Ale kiedy program wykonuje wywołanie do miejsca, w którym kompilator nie widzi, co się dzieje, nie jest już bezpieczne dla kompilatora, aby dokonywać żadnych założeń. Stąd kompilator wygeneruje kod, który zawsze czyta bezpośrednio z pamięci.

Ale uważaj na dzień, kiedy twoja funkcja g () stanie się inline (z powodu jawnych zmian lub z powodu sprytu kompilatora/linkera), Twój kod może się zepsuć, jeśli zapomnisz słowa kluczowego volatile!

Dlatego polecam dodać słowo kluczowe volatile nawet jeśli Twój program wydaje się działać bez. Sprawia, że intencje są jaśniejsze i bardziej wyraziste w odniesieniu do przyszłych zmian.

 0
Author: Joachim,
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
2017-10-23 11:53:54

We wczesnych czasach C Kompilatory interpretowałyby wszystkie operacje odczytu i zapisu lvalu jako operacje pamięci, które miały być wykonywane w tej samej kolejności, co odczyty i zapisy występujące w kodzie. Wydajność można by znacznie poprawić w wielu przypadkach, gdyby kompilatorom dano pewną swobodę w ponownym porządkowaniu i konsolidacji operacji, ale był z tym problem. Nawet operacje były często określone w określonej kolejności tylko dlatego, że konieczne było ich sprecyzowanie w jakiś porządek, a więc programista wybrał jedną z wielu równie dobrych alternatyw, nie zawsze tak było. Czasami ważne jest, aby pewne operacje występowały w określonej sekwencji.

Dokładnie, które szczegóły sekwencjonowania są ważne, będą się różnić w zależności od platformy docelowej i pola aplikacji. Zamiast zapewnić szczególnie szczegółową kontrolę, Standard wybrał prosty model: jeśli sekwencja dostępu odbywa się za pomocą lvalu, który nie jest qualified volatile, kompilator może zmienić kolejność i skonsolidować je według własnego uznania. Jeśli akcja jest wykonywana z volatile-qualified lvalue, implementacja jakości powinna oferować wszelkie dodatkowe gwarancje zamawiania, które mogą być wymagane przez kod ukierunkowany na zamierzoną platformę i pole aplikacji, bez konieczności stosowania niestandardowej składni.

Niestety, zamiast identyfikować Gwarancje potrzebne programistom, wiele kompilatorów zdecydowało się zaoferować minimum gwarancje wymagane przez normę. To czyni volatile znacznie mniej użytecznym niż powinno być. Na przykład w gcc lub clang programista, który musi zaimplementować podstawowy "hand-off mutex "[taki, w którym zadanie, które zdobyło i wydało mutex, nie zrobi tego ponownie, dopóki inne zadanie tego nie zrobi], musi zrobić jedną z czterech rzeczy: {]}

  1. Umieścić akwizycję i wydanie mutex w funkcji, której kompilator nie może wbudować i do której nie może zastosować całego programu Optymalizacja.

  2. Kwalifikuje wszystkie obiekty strzeżone przez mutex jako volatile -- coś, co nie powinno być konieczne, jeśli wszystkie dostępy nastąpią po uzyskaniu mutexu i przed jego zwolnieniem.

  3. Użyj poziomu optymalizacji 0, aby zmusić kompilator do generowania kodu tak, jakby wszystkie obiekty, które nie są kwalifikowane register, były volatile.

  4. Użyj dyrektyw specyficznych dla gcc.

Natomiast przy użyciu kompilatora wyższej jakości, który jest bardziej nadaje się do programowania systemów, takich jak icc, można by mieć inną opcję:

  1. upewnij się, że zapis z kwalifikacją volatile jest wykonywany wszędzie tam, gdzie potrzebne jest pozyskanie lub zwolnienie.

Uzyskanie podstawowego mutex ' a wymaga volatile read (aby sprawdzić, czy jest gotowy) i nie powinno wymagać volatile write (druga strona nie będzie próbowała ponownie go zdobyć, dopóki nie zostanie mu zwrócona), ale konieczność wykonania bezsensownego volatile write jest nadal lepsza niż jakakolwiek z opcji dostępne pod gcc lub clang.

 0
Author: supercat,
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
2018-07-30 17:01:03