2015-01-08 16 views
6

Dokumentacja Intel wCzy atom x86 CMPXCHG jest atomowy?

http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf

mówi

„Ta instrukcja może być używany z przedrostkiem LOCK, aby umożliwić instrukcja do wykonania atomowo”.

Moje pytanie brzmi

  1. Czy CMPXCHG pracować z adresu pamięci? Z dokumentu nie wynika, ale czy ktoś może potwierdzić, że działa tylko z rzeczywistą wartością w rejestrach, a nie z adresem pamięci?

  2. Jeśli CMPXCHG nie jest atomowy, a poziom języka wysokiego poziomu CAS musi zostać zaimplementowany poprzez LOCK CMPXCHG (z prefiksem LOCK), jaki jest cel wprowadzenia takiej instrukcji?

+0

Oczywiście można użyć adresu pamięci, to wszystko. Pierwszy operand jest typu r/m, więc masz. I jak możesz przedłużyć instrukcję 'lock', jeśli sama nie istnieje? – harold

+0

@harold Nie bardzo rozumiem, co nie istnieje. Przedrostek z LOCK, jeśli chcesz, aby instrukcja była atomowa. Czy CMPXCHG, bez prefiksu LOCK, jest atomowe, czy nie? –

+0

Nie, ale w pytaniu 2 zdaje się pan pytać, dlaczego istnieje "cmpxchg bez zamka", co jest dziwne, skoro kombinacja nie może istnieć bez części - jeśli nie to miałeś na myśli, to czy możesz to wyjaśnić? – harold

Odpowiedz

9

Wymieszałeś blokady wysokiego poziomu z niskopoziomową funkcją procesora o nazwie LOCK.

Wysokopoziomowe blokady, których algorytmy bez blokowania próbują uniknąć, mogą ochronić dowolne fragmenty kodu, których wykonanie może zająć dowolny czas, a zatem te blokady będą musiały wprowadzić wątki w stan oczekiwania, dopóki blokada nie będzie dostępna, co jest kosztowne operacja, np sugeruje utrzymanie kolejki oczekujących wątków.

Jest to zupełnie inna sprawa niż funkcja prefiksu CPU LOCK, która chroni pojedynczą instrukcję i dlatego może przechowywać inne wątki tylko podczas trwania tej pojedynczej instrukcji. Ponieważ jest to zaimplementowane przez sam procesor, nie wymaga dodatkowego oprogramowania.

Dlatego wyzwaniem związanym z opracowywaniem algorytmów pozbawionych blokady nie jest całkowite usunięcie synchronizacji, sprowadza się ona do zredukowania krytycznej sekcji kodu do pojedynczej operacji atomowej, która zostanie dostarczona przez sam procesor.

+0

Czy to jest prawidłowe stwierdzenie, że CMPXCHG wciąż trzyma blokadę, która różni się od blokady poziomu programu (np. Blokada JVM)? –

+1

@Rohit Sachan: można powiedzieć, że to się utrzymuje Blokada BUS, ale ponieważ dotyczy to każdego dostępu do pamięci, jedyną różnicą jest to, że jest ona przechowywana dla dwóch dostępów do pamięci wykonanych przez pojedynczą instrukcję i, co ważniejsze, jest to po prostu mylące, gdy mówimy o "programowaniu bez blokady". Innymi słowy, powinieneś zawsze dbać o to, czy dyskusja dotyczy architektury sprzętowej czy programowej ... – Holger

+2

Myślę, że OP częściowo pyta "jaki jest sens" cmpxchg "bez' blokady'? ". Zobacz [moja odpowiedź] (https://stackoverflow.com/questions/27837731/is-x86-cmpxchg-atomic/44273130#44273130): Intel zaprojektował to w ten sposób, ponieważ jest użyteczny w systemie jednoprocesorowym. –

2

zamka prefiks jest, aby zablokować dostęp do pamięci dla bieżącego polecenia, tak aby inne polecenia, które są w przygotowaniu procesora może uzyskać dostępu do pamięci w tym czasie. Używając prefiksu LOCK, wykonanie polecenia nie zostanie przerwane przez inne polecenie w potoku CPU z powodu dostępu do pamięci innych poleceń wykonywanych w tym samym czasie. Instrukcja INTEL mówi:

Przedrostek LOCK może być dołączany wyłącznie do następujących w strukcją i tylko do tych form instrukcją gdzie docelowy operandów jest operand Pamięć: ADD, ADC, I, BTC , BTR, BTS, CMPXCHG, CMPXCH8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD i XCHG. Jeśli prefiks LOCK jest używany z jedną z tych instrukcji i operand źródłowy jest operandem pamięci, może zostać wygenerowany niezdefiniowany wyjątek kodu operacyjnego (#UD).

6

Wydaje się, że część tego, czego naprawdę pytaniem jest:

Dlaczego nie jest lock prefiks niejawny dla cmpxchg z argumentu pamięci, like it is for xchg?

Prostą odpowiedzią (którą dali inni) jest to, że Intel zaprojektował ją w ten sposób. Ale to prowadzi do pytania:

Dlaczego Intel to zrobił? Czy istnieje przypadek użycia dla cmpxchg bez lock?

W systemie pojedynczego procesora, cmpxchgjest atomowej w odniesieniu do innych wątków, lub jakikolwiek inny kod uruchomiony na tym samym rdzeniu procesora. (Ale nie dla "systemowych" obserwatorów, takich jak odwzorowane w pamięci urządzenia I/O, czy też urządzenia robiące DMA czyta normalną pamięć, więc lock cmpxchg było istotne nawet w projektach jednoprocesorowych CPU).

Przełączniki kontekstu mogą się zdarzyć tylko w przypadku przerwania, a przerywanie następuje przed lub po instrukcji, a nie w środku. Każdy kod działający na tym samym procesorze będzie oznaczał, że cmpxchg jest w pełni wykonany lub wcale nie jest.


Na przykład jądro Linux jest zwykle skompilowany z obsługą SMP, więc używa lock cmpxchg dla atomowej CAS. Ale po uruchomieniu w systemie z jednym procesorem, będzie łatał prefiks lock do nop wszędzie tam, gdzie kod był wstawiony, ponieważ nopcmpxchg działa znacznie szybciej niż lock cmpxchg. Aby uzyskać więcej informacji, zobacz: LWN article about Linux's "SMP alternatives" system. Może nawet przywrócić do prefiksów lock przed podłączeniem na gorąco drugiego procesora.

Więcej o atomowości pojedynczych instrukcji w systemach jedno- in this answer, aw @supercat's answer + comments ON może być num++ atomowy dla int num. Zobacz my answer there, aby uzyskać wiele szczegółowych informacji o tym, jak atomowość naprawdę działa/jest zaimplementowana w instrukcjach read-modify-write, takich jak lock cmpxchg.


(To samo rozumowanie dotyczy również cmpxchg8b/cmpxchg16b i xadd, które zwykle wykorzystywane wyłącznie do synchonization/ops atomowych, aby nie zrobić jednowątkowy uruchomić kod szybciej. Oczywiście pamięci przeznaczenia add [mem], reg jest przydatna poza obudowa lock add [mem], reg.)

+0

"Ale po uruchomieniu w systemie jednoprocesorowym łata prefiks blokady do nop wszędzie tam, gdzie kod został wstawiony, ponieważ nop cmpxchg działa znacznie szybciej niż blokada cmpxchg." Zakładam, że masz na myśli kompilacje w systemie jednoprocesorowym? Ponieważ nie jestem świadomy, system operacyjny może łatać takie skompilowane instrukcje w czasie wykonywania. –

+0

@AlexSuo: Nie, system Linux [SMP alternatives] (https://lwn.net/Articles/164121/) naprawdę naprawia obraz jądra w systemach UP. (I BTW, gdyby była to wyłącznie kompilacja, zależałaby od tego, czy budowałeś * na * system UP, a nie * na * systemie UP. Myślę, że jeśli pominiesz 'CONFIG_SMP', niektóre blokady/rzeczy synchronizacji można całkowicie pominąć, zamiast być łatane w NOP podczas startu systemu, ale w dzisiejszych czasach prawdopodobnie nie tak dużo, zwłaszcza przy standardowym 'CONFIG_PREEMPT', który pozwala na uprzednie zneutrowanie kodu jądra.) –

Powiązane problemy