2010-03-18 12 views
30

Czy operatory "modyfikuj" takie jak +=, |=, &= itd. Są atomowe?Czy + =, | =, & = itd. Atomowe?

wiem ++ jest atomowy (jeśli wykonuje x++; w dwóch różnych wątków „jednocześnie”, zawsze skończyć z x wzrosła o 2, w przeciwieństwie do x=x+1 z optymalizacją wyłączony.)

Co Zastanawiam jest czy variable |= constant, a podobieństwa są bezpieczne dla wątków lub czy muszę je chronić za pomocą muteksu?

(... czy jest to zależne od procesora? W tym przypadku, jak to jest na ramieniu?)

+1

Które ARM? Architektura v6 (ARM10) i nowsze wersje mogą zapewniać operacje atomowe, jeśli kompilator je obsługuje lub uruchamiasz własny zespół. Wcześniejsze architektury nie. –

+0

gcc ma wbudowane operacje atomowe: http://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Atomic-Builtins.html#Atomic-Builtins; uwaga: "Nie wszystkie operacje są obsługiwane przez wszystkie docelowe procesory" – Christoph

+0

jest Windows API dla zablokowanego dostępu zmiennego: http://msdn.microsoft.com/en-us/library/ms684122%28v=VS.85%29.aspx –

Odpowiedz

72

Mylisz się. Nie ma gwarancji, że ++ jest atomowe i nie ma go dla operatorów złożonych, ani dla żadnej operacji w C++.

+3

Co oznacza, że ​​jest to zależne od procesora. W architekturach jednordzeniowych, które dopuszczają 'inc [adres]', jest to zdecydowanie atomowa. –

+1

Przynajmniej dopóki C++ 0x: "Ta klauzula opisuje komponenty dla drobnoziarnistego dostępu atomowego. Ten dostęp jest zapewniany przez operacje na obiektach atomowych." [29,1/1 w projekcie n3035]. –

+24

@SF Nie, nie jest. Jest to specyficzne dla kompilatora.Tylko dlatego, że architektura procesora ma instrukcję, nie oznacza, że ​​kompilator użyje jej w sposób, który Twoim zdaniem powinien, jeśli w ogóle ją używa. –

6

dla zmiany wartości były widoczne w całej rdzeni, a + = (na przykład) musiałaby załadowania wartości dodać przyrost, a następnie przechowywać. Oznacza to, że operacja nie będzie miała charakteru atomowego..

Aby zapewnić atomowość, należy odpowiednio zabezpieczyć działanie.

2

++ może być atomowy na kompilatora/platformy, ale w C++ specyfikacja nie określa się atomowy.

Jeśli chcesz się upewnić, aby zmodyfikować wartość w sposób atomowej, należy użyć metody jest właściwa, jak zblokowane * na oknach.

To samo dla wszystkich innych procedur. Jeśli chcesz wykonywać operacje atomowe, powinieneś używać odpowiednich połączeń, a nie standardowych.

2

Nie ma operatora z C lub C++ z gwarantowaną atomową. Mogą być na twojej platformie, ale nie będziesz mieć pewności. Zazwyczaj jedyną operacją, która jest atomowa jest instrukcja Test i Set, która jest zwykle dostępna na większości nowoczesnych procesorów w jakiejś formie jako podstawa do implementacji semaforów.

9

x++ jest często realizowany w 3 instrukcji: Czytaj X do rejestru, przyrost go, a następnie zapisz go z powrotem do pamięci.

Twój wątek może zostać uprzedzony między tymi dwoma.

+1

W przypadku niektórych procesorów nawet pojedyncze instrukcje mogą być nieatomowe. –

0

Warto wspomnieć, że te podmioty mogą być przeciążone, więc z pewnością może być ogólna gwarancja, że ​​nie są one atomowej dla wszystkich klas.

+1

Nie można ich przeciążać na liczbach całkowitych, o czym myślę chodzi. –

+0

Zgoda, ale to nie mówi, dlatego uważam, że warto o tym wspomnieć. – Oddthinking

0

Nawet jeśli ++ jest operacją atomową, to nie oznacza, te dwa wątki powodują, że ++x będzie dokładnie o dwa wyżej. Musisz jakoś zsynchronizować wątki lub w inny sposób niekoniecznie zobaczą nawzajem swoje zmiany.

0

trzeba chronić swoją zmienną, z mutex na przykład

2

To'zarówno kompilatora i CPU zależne. Niektóre zestawy instrukcji dostarczają instrukcje atomowe dla nich (na intach wielkości maszyny).

Nie można jednak zagwarantować, że kompilator użyje tych instrukcji i nie zoptymalizuje kodu w sposób bezpieczny dla wątków. Musisz albo napisać rutynę w zespole, albo użyć specyficznej dla kompilatora techniki (takiej jak instrinsics), która zapewnia atomowość (lub użyć biblioteki, która używa jednej z tych technik).


Konkretnie na ramieniu: ORR/ADD/i instrukcje wziąć dwa operandy i umieść wynik w rejestrze. Każdy operand może być tym samym rejestrem co rejestr wyników, więc może być używany jako atomowy | =, + =, & =.

Oczywiście wynik jest umieszczany w rejestrze, a pierwszy operand musi również pochodzić z rejestru, więc musisz się upewnić, że obciążenia rejestru są wykonane atomowo.

1

powielać skierowana była tutaj, a to wymaga aktualizacji. „Nowy” język C11 umożliwia atrybut atomową, która przyznaje, że:

_Atomic int a; 
... 
a += 3 

mogą być kompilowane do z (atomowego) nieograniczonej pętli. Dzięki za standardy prezentów, naprawdę żałuję, że tego nie zrobiłeś.

1: w niektórych architekturach operacje atomowe są możliwe tylko w pamięci obsługującej określone protokoły dostępu. ARMv7, MIPS na przykład włączyć sekwencję do:

do { 
    x = LoadLinked(a) + 3; 
} while !StoreConditional(x, &a); 

ale LoadLinked/StoreConditional jest niezdefiniowana dla niektórych typów pamięci/pamięci podręcznej. Ciesz się z debugowania tego.

2: Powiązane jest fałszywe udostępnianie które jest artefaktem LoadLinked, StoreConditional działającym na liniach pamięci podręcznej (np. 32, 64, 256 bajtów), a nie podblokach. A więc: _Atomic int a [4]; może wymagać 4 * rozmiaru linii pamięci podręcznej (czyli 1024 bajtów), aby bezpiecznie zezwalać na równoczesne operacje atomowe na [n] i [n + 1], ponieważ 4 jednostki centralne mogą być w stanie zaktualizować [0..3], ale nigdy kolejny.

Mam nadzieję, że następny standard rozpozna nieodłączne niepowodzenie dekoracji atrybutów i przywróci c89 jako prawowity standard C.

Powiązane problemy