Co to jest ogrodzenie pamięci?

Odpowiedzi:

115

Aby zwiększyć wydajność, nowoczesne procesory często wykonują instrukcje poza kolejnością, aby maksymalnie wykorzystać dostępny układ scalony (w tym odczyt / zapis pamięci). Ponieważ sprzęt wymusza integralność instrukcji, nigdy nie zauważysz tego w pojedynczym wątku wykonania. Jednak w przypadku wielu wątków lub środowisk z pamięcią ulotną (na przykład mapowane w pamięci operacje we / wy) może to prowadzić do nieprzewidywalnego zachowania.

Ogrodzenie / bariera pamięci to klasa instrukcji, które oznaczają, że odczytywanie / zapisywanie pamięci odbywa się w oczekiwanej kolejności. Na przykład „pełne ogrodzenie” oznacza, że ​​wszystkie odczyty / zapisy przed ogrodzeniem są zakończone przed tymi za ogrodzeniem.

Uwaga: ogrodzenia pamięci to koncepcja sprzętowa. W językach wyższego poziomu jesteśmy przyzwyczajeni do radzenia sobie z muteksami i semaforami - można je z powodzeniem zaimplementować za pomocą ogniw pamięciowych na niskim poziomie i jawne stosowanie barier pamięci nie jest konieczne. Korzystanie z barier pamięci wymaga dokładnego zbadania architektury sprzętowej i częściej występuje w sterownikach urządzeń niż w kodzie aplikacji.

Zmiana kolejności procesora różni się od optymalizacji kompilatora - chociaż artefakty mogą być podobne. Musisz podjąć osobne kroki, aby zatrzymać zmianę kolejności twoich instrukcji przez kompilator, jeśli może to spowodować niepożądane zachowanie (np. Użycie słowa kluczowego volatile w C).

Gwaredd
źródło
26
Nie sądzę, aby ulotność była wystarczająca, aby zatrzymać zmianę kolejności kompilatora; AFAIK upewnia się tylko, że kompilator nie może buforować wartości zmiennej. Jądro Linuksa używa rozszerzenia gcc ( asm __volatile __ (""::: "memory")) do tworzenia pełnej bariery optymalizacji kompilatora.
CesarB
5
prawda, volatile nie jest świadomy wątków, ale można go użyć do zatrzymania kompilatora stosującego pewne optymalizacje - nie ma to związku z płotami;)
Gwaredd
3
(.NET CLR) ulotne odczyty to ograniczenia pobierania, zapisy to ograniczenia wydania. Operacje blokowane są pełne, podobnie jak metoda MemoryBarrier.
Luke Puplett
3
Ciekawą lekturę o słowie kluczowym volatile w .net można znaleźć tutaj albahari.com/threading/part4.aspx#_NonBlockingSynch Strona zawiera wiele przydatnych informacji na temat wątków w języku c #
Bas Smit
developerWorks ma dobry [artykuł] [1] na temat modelu pamięci masowej PowerPC. [1]: ibm.com/developerworks/systems/articles/powerpc.html
Iouri Goussev
17

Kopiowanie mojej odpowiedzi na inne pytanie: Jakie sztuczki robi procesor, aby zoptymalizować kod? :

Najważniejszą z nich byłaby zmiana kolejności dostępu do pamięci.

W przypadku braku barier pamięci lub instrukcji serializacji procesor może zmieniać kolejność dostępów do pamięci. Niektóre architektury procesorów mają ograniczenia dotyczące tego, ile mogą zmienić kolejności; Alpha jest znana z tego, że jest najsłabsza (tj. Taka, która może najbardziej zmienić kolejność).

Bardzo dobre podejście do tematu można znaleźć w dokumentacji źródeł jądra Linux, w Documentation / memory-barriers.txt .

W większości przypadków najlepiej jest używać blokujących prymitywów z kompilatora lub biblioteki standardowej; są one dobrze przetestowane, powinny mieć wszystkie niezbędne bariery pamięci i prawdopodobnie są dość zoptymalizowane (optymalizacja prymitywów blokujących jest trudna; nawet eksperci mogą czasami je pomylić).

CesarB
źródło
Jak to wpływa na przepływ zmiany kolejności? Kiedy powiedziałeś Alpha is known for being the weakest, dlaczego weakest? Czy nie lepiej, że będzie zmieniał kolejność więcej, dzięki czemu będzie znacznie szybsza realizacja? (Nie jestem użytkownikiem alfa, ale pytam o efekt very reorderingvs restricted reordering). Jakie są więc wady zmiany kolejności partii (z wyjątkiem ryzyka nieokreślonego zachowania, ale myślę, że większość nowoczesnych procesorów powinna była rozwiązać dobry sposób zmiany kolejności i zaimplementować tylko zdefiniowaną zmianę kolejności, w przeciwnym razie nie miałoby to sensu).
Herdsman
8

Z mojego doświadczenia wynika, że ​​odnosi się to do bariery pamięci , która jest instrukcją (jawną lub niejawną) synchronizowania dostępu do pamięci między wieloma wątkami.

Problem występuje w połączeniu nowoczesnych, agresywnych kompilatorów (mają niesamowitą swobodę zmiany kolejności instrukcji, ale zwykle nic nie wiedzą o twoich wątkach) i nowoczesnych procesorów wielordzeniowych.

Dobrym wprowadzeniem do problemu jest „DeklaracjaPodwójnie sprawdzone blokowanie jest uszkodzone ” ”. Dla wielu był to sygnał ostrzegawczy, że są smoki.

Niejawne bariery pełnej pamięci są zwykle zawarte w procedurach synchronizacji wątków platformy, które obejmują jej rdzeń. Jednak do programowania bez zamków i wdrażania niestandardowych, lekkich wzorców synchronizacji często potrzebujesz tylko bariery lub nawet bariery jednokierunkowej.

peterchen
źródło
2

Wikipedia wie wszystko ...

Bariera pamięci, znana również jako membar lub ogrodzenie pamięci, to klasa instrukcji, które powodują, że jednostka centralna (CPU) wymusza ograniczenie porządkowania operacji pamięciowych wydanych przed i po instrukcji bariery.

Procesory wykorzystują optymalizacje wydajności, które mogą powodować wykonanie poza kolejnością, w tym operacje ładowania pamięci i przechowywania. Zmiana kolejności operacji pamięciowych zwykle pozostaje niezauważona w ramach pojedynczego wątku wykonania, ale powoduje nieprzewidywalne zachowanie we współbieżnych programach i sterownikach urządzeń, chyba że jest dokładnie kontrolowane. Dokładny charakter ograniczenia porządkowania zależy od sprzętu i jest definiowany przez model pamięci architektury. Niektóre architektury zapewniają wiele barier dla wymuszania różnych ograniczeń kolejności.

Bariery pamięci są zwykle używane podczas implementowania kodu maszynowego niskiego poziomu, który działa w pamięci współużytkowanej przez wiele urządzeń. Taki kod obejmuje prymitywy synchronizacji i niezablokowane struktury danych w systemach wieloprocesorowych oraz sterowniki urządzeń, które komunikują się ze sprzętem komputerowym.

Omar Kooheji
źródło