Oznacza to, że jeśli wykonujesz modyfikację struktury danych, ważną cechą jest to, że możesz wykonać wszystkie mody w prywatnej strukturze danych, a następnie zamienić modyfikacje w pojedynczej instrukcji atomowej.
Swoboda blokowania jest zwykle najłatwiejsza, gdy struktury danych są niezmienne ( czysto funkcjonalne ). Po prostu trzymasz globalny wskaźnik do bieżącej wersji struktury danych. Czytelnicy nie muszą niczego blokować. Modyfikacje struktury danych są dokonywane poprzez zamianę wskaźnika globalnego na jedną niezmienną strukturę danych na drugą.
Na przykład: jeśli masz drzewo funkcjonalnie zrównoważone, to:
Zapisz bieżący wskaźnik globalny do katalogu głównego drzewa.
Utwórz nowe drzewo, które wstawia lub usuwa węzeł. (Jest to logarytmiczne w czasie i przestrzeni w liczbie węzłów obecnie w drzewie i obejmuje tworzenie nowych węzłów od punktu modyfikacji do katalogu głównego i po prostu wskazywanie wszystkiego nowego na stare części poprzedniej wersji struktury danych. )
Atomowo porównaj i zamień globalny wskaźnik na katalog główny. (Należy zauważyć, że może się to nie udać, jeśli między chwilą zarejestrowania starego wskaźnika głównego a tą zdarzy się kolejna modyfikacja. Jeśli tak się stanie, wróć do kroku 1 i spróbuj ponownie. Jest to tak zwana „optymistyczna kontrola współbieżności”).
Zauważ, że najważniejsze jest to, co powiedziałem powyżej o potrzebie utrzymania niezmienników reprezentacji. Zwykle nie wystarczy mieć algorytm, który atomowo dokonuje zmiany pośrodku drzewa. Dlaczego? Na przykład: możesz mieć wątek czytelnika, który jest w trakcie wykonywania przedprzebiegowego przejścia przez drzewo. Jeśli zmodyfikujesz węzeł, który jest przodkiem węzła, który obecnie czytają, unieważnisz warunki wstępne, które według nich wymusiły. Czytelnik musi być w stanie pracować ze strukturą danych dokładnie tak, jak było przed wprowadzeniem zmiany lub dokładnie tak, jak będzie po dokonaniu zmiany. Nie coś pomiędzy.
Myślę, że techniki aktywnego oczekiwania, np. Przy porównywaniu i zamianie, są zwykle nazywane „blokadą bez blokady”, więc istnieją pewne sposoby wyjścia, nawet w przypadku zmiennych ustawień.
Raphael
Nie znam terminu aktywnego oczekiwania (a Google nie pomaga). (Jeśli mówisz o pracy Kogana i Petranka, to pokazuje, jak zamienić algorytmy bez blokady w bez czekania.) Dodałem edycję o tym, jak możesz poradzić sobie ze zmiennością w zakresie swobody blokowania w ogóle.
Wandering Logic
Przez „aktywne czekanie” rozumiem coś takiego, while ( !P ) { noOp(); } doWork();gdzie noOpmoże być coś sleeppodobnego.
Raphael
W części „ Edycja” wspomniałeś o technice, dzięki której zmienne struktury danych są blokowane. Jak wskazano, kopiujemy całą strukturę danych, modyfikujemy kopię, a następnie używamy prymitywu CAS. Jak jednak uczynić Copykrok atomowym? Wydaje się, że jest to kolejny trudny problem atomic snapshot.
hengxin
@hengxin: pomyśl o prymitywnym CAS jako operatorze „publikuj”. Przed opublikowaniem struktury danych tylko wątek dokonujący modyfikacji ma do niej dostęp. Po opublikowaniu struktury danych jest ona niezmienna. Krok kopiowania nie musi być atomowy, ponieważ jedyną rzeczą, którą może kopiować wątek, jest opublikowana wersja, która jest niezmienna. Jeśli dwa wątki jednocześnie próbują mutować, oba kopiują tę samą niezmienną strukturę danych, modyfikują swoje kopie lokalne, a następnie jedna z operacji CAS kończy się powodzeniem, a druga kończy się niepowodzeniem. Ten, który zawiedzie, musi zostać skopiowany i zaktualizowany.
Odpowiedzi:
Oznacza to, że jeśli wykonujesz modyfikację struktury danych, ważną cechą jest to, że możesz wykonać wszystkie mody w prywatnej strukturze danych, a następnie zamienić modyfikacje w pojedynczej instrukcji atomowej.
Swoboda blokowania jest zwykle najłatwiejsza, gdy struktury danych są niezmienne ( czysto funkcjonalne ). Po prostu trzymasz globalny wskaźnik do bieżącej wersji struktury danych. Czytelnicy nie muszą niczego blokować. Modyfikacje struktury danych są dokonywane poprzez zamianę wskaźnika globalnego na jedną niezmienną strukturę danych na drugą.
Na przykład: jeśli masz drzewo funkcjonalnie zrównoważone, to:
Zauważ, że najważniejsze jest to, co powiedziałem powyżej o potrzebie utrzymania niezmienników reprezentacji. Zwykle nie wystarczy mieć algorytm, który atomowo dokonuje zmiany pośrodku drzewa. Dlaczego? Na przykład: możesz mieć wątek czytelnika, który jest w trakcie wykonywania przedprzebiegowego przejścia przez drzewo. Jeśli zmodyfikujesz węzeł, który jest przodkiem węzła, który obecnie czytają, unieważnisz warunki wstępne, które według nich wymusiły. Czytelnik musi być w stanie pracować ze strukturą danych dokładnie tak, jak było przed wprowadzeniem zmiany lub dokładnie tak, jak będzie po dokonaniu zmiany. Nie coś pomiędzy.
źródło
while ( !P ) { noOp(); } doWork();
gdzienoOp
może być cośsleep
podobnego.Copy
krok atomowym? Wydaje się, że jest to kolejny trudny problematomic snapshot
.