std:: Atomic decrement and comparison

Na następującym kodzie:

std::atomic<int> myint; //Shared variable
//(...)
if( --myint == 0) {
    //Code block B
}

Czy to możliwe, że więcej niż jeden wątek ma dostęp do bloku, który nazwałem "Blok kodu B"?

Proszę wziąć pod uwagę, że nie dojdzie do przepełnienia, że " if " jest wykonywane jednocześnie przez więcej niż jeden wątek, że jedyną modyfikacją myint w całym programie jest --myint wewnątrz if I że myint jest inicjalizowana z wartością dodatnią.

Author: R. Martinho Fernandes, 2011-10-26

3 answers

C++0x papier N2427 (atomics) stwierdza mniej więcej co następuje. Zmieniłem nieco sformułowanie, aby było łatwiejsze do odczytania dla konkretnej sytuacji, części, które zmieniłem są w pogrubione :

Efekty: Atomicznie zastąp wartość w obiekcie wynikiem decrement zastosowanego do wartości w obiekcie I podanego argumentu. Pamięć jest naruszona zgodnie z zamówieniem. Operacje te to read-modify-write operacje w sensie definicji "synchronizes with" w [Nowa sekcja dodana przez N2334 lub następcę], a zatem zarówno taka operacja, jak i ocena, która wytworzyła wartość wejściową, synchronizują się z dowolną oceną, która odczytuje zaktualizowaną wartość.

Zwraca: Atomicznie wartość obiektu bezpośrednio przed dekrementem.

Operacja atomowa gwarantuje, że operator decrement zwróci wartość posiadaną przez zmienną bezpośrednio przed operacją jest to atomic, więc nie może być żadnej wartości pośredniej z aktualizacji przez inny wątek.

Oznacza to, że poniżej znajdują się jedyne możliwe wykonanie tego kodu z 2 wątkami:

(Initial Value: 1)
Thread 1: Decrement 
Thread 1: Compare, value is 0, enter region of interest
Thread 2: Decrement
Thread 2: Compare, value is -1, don't enter region

Lub

(Initial Value: 1)
Thread 1: Decrement 
Thread 2: Decrement
Thread 1: Compare, value is 0, enter region of interest
Thread 2: Compare, value is -1, don't enter region

Przypadek 1 jest nieciekawym oczekiwanym przypadkiem.

Przypadek 2 przeplata operacje dekrementacyjne i wykonuje operacje porównawcze później. Ponieważ operacja decrement-and-fetch jest atomowa , jest to niemożliwe dla wątku 1, aby otrzymać wartość inną niż 0 dla porównania. To nie może otrzymać a -1, ponieważ operacja była atomowa... odczyt odbywa się w momencie dekrementacji, a Nie w momencie porównania. Więcej wątków nie zmieni tego zachowania.

 18
Author: SoapBox,
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-10-26 23:21:47

Nie jest oczywiste, że blok kodu będzie zawsze wykonywany. Jeśli operator " -- " jest zaimplementowany w taki sposób, że przechowuje starą wartość w zwracanej wartości i zmniejsza się w pojedynczej instrukcji atomowej( jestem prawie pewien, że x86 ma takie instrukcje), to tak, powinien działać jak blok wzajemnego wykluczenia dla wielu wątków. Nie jestem pewien, jak to działa domyślnie, ale odpowiedź leży prawdopodobnie w nowym standardzie dokumentacja:

Http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html

 1
Author: André Ferreira Bem Silva,
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-10-26 22:11:08

Nie nie jest możliwe, że więcej niż jeden wątek wchodzi do bloku, biorąc pod uwagę twoje ograniczenia. Ale nie ma też gwarancji, że jakikolwiek wątek kiedykolwiek wejdzie do tego bloku:

thread A: decrement myint to 0

thread B: decrement myint to -1

thread A: compare to 0 -> false -> don't enter (and neither anyone else)

Jeśli jest to problem (który zakładam), to ten kod nie będzie działał (przynajmniej nie Zawsze ).

 -1
Author: Christian Rau,
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-10-26 21:59:02