Po, ngarkesat/magazinat e rreshtuara 8 bajt garantohen atomike nga x86 ISA, që nga P5 Pentium. Pse caktimi i numrave të plotë është në një linjë të natyrshme atomike të ndryshueshme në x86?
Por kjo është C++; nuk ka asnjë garanci që dyqanet dhe ringarkimet nuk janë të optimizuara larg. Shkrimi në një fill dhe leximi në një tjetër është sjellje e padefinuar në C++; përpiluesit lejohen të supozojnë se nuk ndodh, thyerja e supozimeve naive. Kjo i lejon ata të mbajnë objekte C++ në regjistra përgjatë leximeve/shkrimeve të shumta, vetëm përfundimisht duke ruajtur vlerën përfundimtare. (duke përfshirë variablat globale ose memorien e drejtuar nga ndonjë tregues.)
Meqenëse nuk e dinit që volatile
ose atomic<double>
nevojiten për këtë arsye, më mirë lexoni për të tjera gjërat që bën atomic<>
për ju, si p.sh. porositja e wrt. operacione të tjera nëse nuk përdorni memory_order_relaxed
(parazgjedhja është seq_cst
që i bën dyqanet të shtrenjta, por në ngarkesat x86 janë ende po aq të lira). Dhe (si volatile
) supozimi se thread-et e tjera mund të kenë modifikuar një objekt midis akseseve në këtë thread. Shikoni A mund të jetë num++ atomike për 'int num'?, disa nga e cila është e rëndësishme për ngarkesat dhe depozitat e FP.
Programimi pa kyçje në C++ nuk është i thjeshtë, nëse nuk keni zero nevojë për sinkronizim / renditje. Atëherë ju "thjesht" duhet të siguroheni që t'i tregoni përpiluesit se çfarë do të thoni, me atomic<T>
, ose si hak me double
.
Meqenëse std::atomic<double>
me mo_relaxed
e GCC nuk përpilohet në mënyrë efikase, ju mund të krijoni të tuajën duke i bërë anëtarët volatile
nëse ju intereson vetëm transportueshmëria. (ose edhe transmetimi në (volatile double*)
si makrot READ_ONCE
/ WRITE_ONCE
të kernelit Linux). Me clang, thjesht mund të përdorni atomic<double>
me memory_order_relaxed dhe gjërat do të përpilohen në mënyrë efikase. Shiko C++20 std::atomic‹float›- std::atomic‹u .specializimet për shembull se çfarë mund të bëni përpara C++20; C++20 shton vetëm shtesë/nën atomike RMW për double
, kështu që ju nuk keni nevojë të rrotulloni tuajën me një lak CAS.
volatile
ndoshta do të vazhdojë të mposhtë vektorizimin automatik, por sigurisht që mund të përdorni _mm_load_pd
ose çfarëdo. (Shih gjithashtu Atomic double floating pika ose ngarkesa/ruajtja e vektorit SSE/AVX në x86_64 - vini re se ngarkesa/magazina SIMD nuk është domosdoshmërisht atomike edhe nëse është e linjës. Gjithashtu e padokumentuar është nëse ato janë atomike për element, megjithëse është< /em> Unë mendoj se është e sigurt të supozohet. Për-element atomiciteti i ngarkesës vektoriale/ruani dhe grumbulloni/shpërndani?)
Kur të përdoret volatile me shumë threading? normalisht kurrë nuk mund të përdoret. , përveç ndoshta si një zgjidhje për GCC që nuk do të emetojë asm efikas për atomic<double>
, dhe ku ne e dimë saktësisht se si volatile
përpilohet në asm.
BTW, ju nevojitet vetëm alignas(8)
për t'u siguruar që anëtarët të jenë të rreshtuar 8 bajt. Përafrimi i strukturës në një linjë të tërë të memories së memories nuk dëmton, përveç nëse humbet hapësirë.
Për performancën: nëse threads të ndryshëm përdorin variabla të ndryshëm në të njëjtën linjë cache, kjo është "false share" dhe e tmerrshme për performancën. Mos i gruponi variablat tuaja të përbashkëta së bashku në një strukturë, përveç nëse ato zakonisht lexohen ose shkruhen si grup. Përndryshe, ju patjetër i dëshironi ato në linja të veçanta memorie 64-bajtëshe.
Vini re se një garë e të dhënave në një volatile
është ende një sjellje e papërcaktuar ISO C++, por nëse jeni duke përdorur GNU C (siç kërkohet nga __attribute__
-ja juaj), është shumë mirë e përcaktuar. Kerneli Linux e përdor atë për atomin e tij të mbështjellë me dorë (së bashku me asm
në linjë për barrierat), kështu që mund të supozoni se nuk do të jetë e pambështetur qëllimisht së shpejti.
TL:DR: në GNU C bën pak a shumë punë të mendosh për volatile
si atomike me mo_relaxed
, për objektet e rreshtuara mjaft të vogla që të jenë atomike natyrale.
27.11.2019
double a
çdo përsëritje në rast se ndryshon, kjo mund të godasë në cache. Ruajtja e fillit B nëdouble b
në të njëjtën linjë sia
do ta zhvlerësojë atë rresht në të gjitha bërthamat e tjera, duke ndërhyrë me fillin A edhe nëse filli A nuk lexon kurrëb
. 27.11.2019