Czym dokładnie jest std:: atomic?
Rozumiem, że std::atomic<>
jest obiektem atomowym. Ale atomowy w jakim stopniu? Według mnie operacja może być atomowa. Co dokładnie oznacza uczynienie obiektu atomowym? Na przykład, jeśli istnieją dwa wątki jednocześnie wykonujące następujący kod:
a = a + 12;
To czy cała operacja (powiedzmy add_twelve_to(int)
) jest atomowa? Czy zmiany w zmiennej atomic (so operator=()
)?
2 answers
Każda instancja i pełna specjalizacja std::atomic reprezentuje typ, na którym różne wątki mogą jednocześnie działać (ich instancje), bez podnoszenia niezdefiniowanego zachowania:
Obiekty typów atomowych są jedynymi obiektami C++, które są wolne od Ras danych; to znaczy, jeśli jeden wątek pisze do obiektu atomowego, podczas gdy inny wątek czyta z niego, zachowanie jest dobrze zdefiniowane.
Ponadto dostęp do obiektów atomowych może ustanowić synchronizacja między wątkami i porządkowanie dostępu do pamięci niematomicznych, jak określono w
std::memory_order
.
std::atomic<>
operacje, które w pre-C++ 11 razy musiały być wykonywane przy użyciu (na przykład) funkcji interlocked Z MSVC lub Atomic bultins W przypadku GCC.
Ponadto, std::atomic<>
daje większą kontrolę, pozwalając na różne rozkazy pamięci , które określają ograniczenia synchronizacji i porządkowania. Jeśli chcesz poczytać więcej o Atomice i pamięci C++ 11 model, te linki mogą być przydatne:
- atomika C++ i porządkowanie pamięci
- W 2007 roku firma została założona przez firmę Atomics, która od 2007 roku zajmuje się projektowaniem i dystrybucją oprogramowania.]}
- C++11 wprowadził ustandaryzowany model pamięci. Co to znaczy? A jak to wpłynie na programowanie w C++?
- współbieżność w C++11
Zauważ, że w typowych przypadkach użycia prawdopodobnie użyłbyś przeciążonej arytmetyki operatory lub inny ich zbiór :
std::atomic<long> value(0);
value++; //This is an atomic op
value += 5; //And so is this
Ponieważ składnia operatora nie pozwala na określenie kolejności pamięci, operacje te będą wykonywane z std::memory_order_seq_cst
, ponieważ jest to domyślna kolejność dla wszystkich operacji atomowych w C++ 11. Gwarantuje sekwencyjną spójność (całkowity porządek globalny) pomiędzy wszystkimi operacjami atomowymi.
W niektórych przypadkach może to nie być wymagane (i nic nie przychodzi za darmo) , więc możesz chcieć użyć bardziej wyraźnego forma:
std::atomic<long> value {0};
value.fetch_add(1, std::memory_order_relaxed); // Atomic, but there are no synchronization or ordering constraints
value.fetch_add(5, std::memory_order_release); // Atomic, performs 'release' operation
Teraz twój przykład:
a = a + 12;
Nie będzie oceniać do pojedynczego atomu op: spowoduje to a.load()
(który jest atomowy), a następnie dodanie między tą wartością a 12
i a.store()
(również atomowy) wyniku końcowego. Jak już wcześniej wspomniałem, std::memory_order_seq_cst
będzie tutaj używany.
Jeśli jednak napiszesz a += 12
, będzie to operacja atomowa (jak już wcześniej wspomniałem) i jest mniej więcej równoważna a.fetch_add(12, std::memory_order_seq_cst)
.
Co do Twojego komentarza:
Zwykły
int
ma ładunki atomowe i sklepy. Jaki jest sens owijania goatomic<>
?
Twoje stwierdzenie jest prawdziwe tylko dla architektur, które zapewniają taką gwarancję atomiczności dla sklepów i / lub obciążeń. Są architektury, które tego nie robią. Ponadto, zwykle wymagane jest, aby operacje były wykonywane na adresach Word- / dword-aligned, aby były atomowe std::atomic<>
jest czymś, co jest gwarantowane na na każdej platformie, bez dodatkowych wymagań. Ponadto pozwala na napisz kod w ten sposób:
void* sharedData = nullptr;
std::atomic<int> ready_flag = 0;
// Thread 1
void produce()
{
sharedData = generateData();
ready_flag.store(1, std::memory_order_release);
}
// Thread 2
void consume()
{
while (ready_flag.load(std::memory_order_acquire) == 0)
{
std::this_thread::yield();
}
assert(sharedData != nullptr); // will never trigger
processData(sharedData);
}
Zauważ, że warunek twierdzenia zawsze będzie prawdziwy (a więc nigdy się nie uruchomi), więc zawsze możesz być pewien, że dane są gotowe po wyjściu pętli while
. Dlatego, że:
-
store()
to flaga jest wykonywana po ustawieniusharedData
(Zakładamy, żegenerateData()
zawsze zwraca coś użytecznego, w szczególności nigdy nie zwracaNULL
) i używastd::memory_order_release
order:
memory_order_release
Operacja sklepu z tą pamięcią wykonuje release operacja: nie można zmienić kolejności odczytów ani zapisów w bieżącym wątku po tym sklepie. wszystkie wpisy w bieżącym wątku są widoczne w inne wątki, które nabywają tę samą zmienną atomową
-
sharedData
jest używane po wyjściu pętliwhile
, a zatem poload()
from flag zwróci niezerową wartość.load()
używastd::memory_order_acquire
kolejność:
std::memory_order_acquire
Operacja ładowania z tą pamięcią order wykonuje operację acquire na dotkniętej lokalizacji pamięci: brak odczytów i zapisów w bieżącym wątek może być ponownie uporządkowany przed tym obciążeniem. wszystkie wpisy w innych wątkach które uwalniają tę samą zmienną atomową są widoczne w bieżącym wątek .
Daje Ci to precyzyjną kontrolę nad synchronizacją i pozwala ci wyraźnie określić, jak Twój kod może/może nie/będzie / nie będzie się zachowywał. Nie byłoby to możliwe, gdyby tylko gwarancją była sama atomiczność. Szczególnie jeśli chodzi o bardzo ciekawe modele synchronizacji, takie jak release-consume ordering .
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-01-24 15:40:02
To kwestia perspektywy... nie można zastosować go do dowolnych obiektów i ich operacje stają się atomowe, ale można użyć podanych specjalizacji dla (większości) typów całkowych i wskaźników.Rozumiem, że
std::atomic<>
sprawia, że obiekt jest atomowy.
a = a + 12;
std::atomic<>
nie (używa wyrażeń szablonowych do) uproszczenia tego do pojedynczej operacji atomowej, zamiast tego Element operator T() const volatile noexcept
wykonuje atomową load()
z a
, Następnie dodaje się dwanaście i operator=(T t) noexcept
robi store(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
2015-08-13 02:42:17