Co to jest blokada w systemie Linux?


32

Chciałbym szczegółowo wiedzieć o blokadach Linuksa; czy ktoś mógłby mi je wyjaśnić?

Odpowiedzi:


34

Blokada spinowa to sposób ochrony udostępnionego zasobu przed modyfikacją przez dwa lub więcej procesów jednocześnie. Pierwszy proces, który próbuje zmodyfikować zasób, „przejmuje” blokadę i kontynuuje swoją drogę, robiąc to, czego potrzebował z zasobem. Wszelkie inne procesy, które następnie próbują uzyskać blokadę, zostają zatrzymane; Mówi się, że „obracają się w miejscu”, czekając na zamek, który zostanie zwolniony przez pierwszy proces, stąd nazwa spin lock.

Jądro Linux używa blokad spinowych do wielu rzeczy, na przykład podczas wysyłania danych do określonego urządzenia peryferyjnego. Większość sprzętowych urządzeń peryferyjnych nie jest zaprojektowana do obsługi wielu jednoczesnych aktualizacji stanu. Jeśli muszą wystąpić dwie różne modyfikacje, jedna musi ściśle przestrzegać drugiej, nie mogą się one nakładać. Blokada obrotowa zapewnia niezbędną ochronę, zapewniając, że modyfikacje są wprowadzane pojedynczo.

Blokady spinowe stanowią problem, ponieważ wirujące bloki rdzenia procesora tego wątku nie wykonują żadnej innej pracy. Podczas gdy jądro Linuksa zapewnia usługi wielozadaniowości działającym pod nim programom użytkownika, ta uniwersalna funkcja wielozadaniowości nie obejmuje kodu jądra.

Ta sytuacja się zmienia i tak było przez większość istnienia Linuksa. W Linuksie jądro było prawie wyłącznie programem jednozadaniowym: za każdym razem, gdy procesor wykonywał kod jądra, używany był tylko jeden rdzeń procesora, ponieważ istniała jedna blokada spinowa chroniąca wszystkie współdzielone zasoby, zwana Big Kernel Lock (BKL ). Począwszy od Linuksa 2.2, BKL powoli dzieli się na wiele niezależnych blokad, z których każda chroni bardziej skoncentrowaną klasę zasobów. Dzisiaj, z jądrem 2.6, BKL nadal istnieje, ale jest używany tylko przez naprawdę stary kod, którego nie można łatwo przenieść do bardziej szczegółowej blokady. Obecnie jest całkiem możliwe, że w pudełku wielordzeniowym każdy procesor działa użyteczny kod jądra.

Ograniczenie użyteczności BKL jest ograniczone, ponieważ jądro Linuksa nie ma ogólnej wielozadaniowości. Jeśli rdzeń procesora zostanie zablokowany podczas wirowania w blokadzie spinania jądra, nie można go powtórzyć, aby zrobić coś innego, dopóki blokada nie zostanie zwolniona. Po prostu siedzi i obraca się, aż zamek zostanie zwolniony.

Blokady obrotowe mogą skutecznie przekształcić potworną 16-rdzeniową skrzynkę w jedno-rdzeniową skrzynkę, jeśli obciążenie jest takie, że każdy rdzeń zawsze czeka na pojedynczy blokadę wirowania. Jest to główny limit skalowalności jądra Linuksa: podwojenie rdzeni procesora z 2 do 4 prawdopodobnie prawie podwoi prędkość Linux-a, ale podwojenie go z 16 do 32 prawdopodobnie nie przy większości obciążeń.


@Warren: Kilka wątpliwości - chciałbym dowiedzieć się więcej o tej blokadzie jądra i jej implikacjach. Nie rozumiem też ostatniego akapitu: „Podwojenie rdzeni procesora z 2 do 4 prawdopodobnie prawie podwoi prędkość Linux-a, ale podwojenie z 16 do 32 prawdopodobnie nie”
Sen

2
Re: implikacje BKL: Myślałem, że wyjaśniłem to powyżej. Mając tylko jedną blokadę w jądrze, za każdym razem, gdy dwa rdzenie próbują zrobić coś chronionego przez BKL, jeden rdzeń jest blokowany, podczas gdy pierwszy kończy korzystanie z chronionego zasobu. Im bardziej drobnoziarniste blokowanie, tym mniejsza szansa, że ​​tak się stanie, tym większe wykorzystanie procesora.
Warren Young,

2
Re: podwojenie: Mam na myśli prawo malejących zwrotów podczas dodawania rdzeni procesora do komputera. Wraz ze wzrostem liczby rdzeni rośnie również szansa, że ​​dwa lub więcej z nich będzie musiało uzyskać dostęp do zasobu chronionego przez konkretną blokadę. Zwiększenie ziarnistości zamka zmniejsza ryzyko takich kolizji, ale dodawanie zbyt wielu również wiąże się z dodatkowymi kosztami. Można to łatwo zobaczyć w superkomputerach, które często mają obecnie tysiące procesorów: większość obciążeń jest na nich nieefektywna, ponieważ nie mogą uniknąć bezczynności wielu procesorów z powodu rywalizacji o współdzielone zasoby.
Warren Young,

1
Chociaż jest to interesujące wyjaśnienie (+1 za to), nie sądzę, że jest skuteczne w przekazywaniu różnicy między spinlockami a innymi rodzajami blokad.
Gilles „SO- przestań być zły”

2
Jeśli ktoś chce poznać różnicę między blokadą spinania a, powiedzmy, semaforem, to jest inne pytanie. Innym dobrym, ale stycznym pytaniem jest, co takiego jest w konstrukcji jądra Linuksa, która sprawia, że ​​spin lock jest dobrym wyborem zamiast czegoś bardziej powszechnego w kodzie użytkownika, takiego jak mutex. Ta odpowiedź jest bardzo rozbieżna.
Warren Young,

11

Blokada spin ma miejsce, gdy proces nieustannie sprawdza, czy blokada ma zostać usunięta. Jest to uważane za złe, ponieważ proces zużywa cykle (zwykle) niepotrzebnie. Nie jest on specyficzny dla Linuksa, ale ogólny wzorzec programowania. I chociaż jest to ogólnie uważane za złą praktykę, jest w rzeczywistości właściwym rozwiązaniem; zdarzają się przypadki, w których koszt korzystania z harmonogramu jest wyższy (pod względem cykli procesora) niż koszt kilku cykli, które ma trwać spinlock.

Przykład spinlocka:

#!/bin/sh
#wait for some program to clear a lock before doing stuff
while [ -f /var/run/example.lock ]; do
  sleep 1
done
#do stuff

Często istnieje sposób na uniknięcie blokady wirowania. W tym konkretnym przykładzie istnieje narzędzie Linux o nazwie inotifywait (zwykle nie jest instalowane domyślnie). Gdyby został napisany w C, wystarczy użyć interfejsu API inotify, który zapewnia Linux.

Ten sam przykład przy użyciu inotifywait pokazuje, jak osiągnąć to samo bez blokady wirowania:

#/bin/sh
inotifywait -e delete_self /var/run/example.lock
#do stuff

Jaka jest tam rola harmonogramu? Czy ma to jakąś rolę?
Sen

1
W metodzie spin lock planista wznawia proces co ~ 1 sekundę, aby wykonać swoje zadanie (czyli po prostu sprawdzić istnienie pliku). W przykładzie inotifywait program planujący wznawia proces dopiero po zakończeniu procesu potomnego (inotifywait). Inotifywait również śpi; program planujący wznawia je tylko wtedy, gdy nastąpi zdarzenie inotify.
Shawn J. Goff,

Jak zatem radzić sobie z tym scenariuszem w systemie z pojedynczym rdzeniem?
Sen

@Sen: Jest to dość dobrze wyjaśnione w Linux Device Drivers .
Gilles „SO- przestań być zły”

1
Ten skrypt bash jest złym przykładem spinlocka. Zatrzymujesz proces, aby przejść do snu. Blokada nigdy nie śpi. Na maszynie z jednym rdzeniem po prostu zawiesza harmonogram i kontynuuje (bez zajętego oczekiwania)
Martin

7

Gdy wątek próbuje uzyskać blokadę, mogą się zdarzyć trzy rzeczy, jeśli się nie powiedzie, może spróbować zablokować, może spróbować i kontynuować, może następnie przejść do trybu uśpienia, informując system operacyjny o przebudzeniu, gdy nastąpi jakieś zdarzenie.

Teraz spróbuj i kontynuuj zajmuje dużo mniej czasu niż próbuj i blokuj. Powiedzmy na chwilę, że „spróbuj i kontynuuj” zajmie mi jednostkę czasu, a „spróbuj i zablokuj” zajmie sto.

Teraz załóżmy na chwilę, że przytrzymanie zamka zajmuje średnio 4 jednostki czasu. Nie warto czekać na 100 jednostek. Zamiast tego piszesz pętlę „spróbuj i kontynuuj”. Przy czwartej próbie zwykle zdobędziesz zamek. To jest blokada obrotu. Nazywa się to, ponieważ nić obraca się w miejscu, dopóki nie dostanie zamka.

Dodatkowym środkiem bezpieczeństwa jest ograniczenie liczby uruchomień pętli. Tak więc w tym przykładzie wykonujesz pętlę for, np. Sześć razy, jeśli zawiedzie, wówczas „próbujesz zablokować”.

Jeśli wiesz, że wątek zawsze blokuje na przykład 200 jednostek, to marnujesz czas komputera na każdą próbę i kontynuowanie.

W końcu blokada spinowa może być bardzo wydajna lub marnotrawiona. Jest to marnotrawstwem, gdy „typowy” czas na trzymanie zamka jest dłuższy niż czas potrzebny na „próbę zablokowania”. Jest skuteczny, gdy typowy czas trzymania zamka jest znacznie krótszy niż czas „próby zablokowania”.

Ps: Książką do przeczytania w wątkach jest „Elementarz wątku”, jeśli nadal możesz go znaleźć.


nić obraca się w miejscu, aż do uzyskania blokady . Czy możesz mi powiedzieć, co to za wirowanie? Czy to tak, jakby chodziło o czekanie w kolejce i uruchamianie go przez program planujący? Może próbuję dostać się na niski poziom, ale wciąż nie mogę utrzymać wątpliwości.
Sen

Zasadniczo wirowanie wśród 3-4 instrukcji w pętli.
Paul Stelian

5

Blokada jest sposobem dla dwóch lub więcej zadań (procesów, wątków) zsynchronizować. W szczególności, gdy oba zadania wymagają przerywanego dostępu do zasobu, z którego może korzystać tylko jedno zadanie naraz, jest to sposób, aby zadania nie wykorzystywały zasobu w tym samym czasie. Aby uzyskać dostęp do zasobu, zadanie musi wykonać następujące kroki:

take the lock
use the resource
release the lock

Przejęcie blokady nie jest możliwe, jeśli już zajęło ją inne zadanie. (Pomyśl o zamku jak o fizycznym tokenie. Albo obiekt znajduje się w szufladzie, albo ktoś ma go w ręce. Tylko osoba trzymająca przedmiot może uzyskać dostęp do zasobu.) Zatem „zabranie zamka” naprawdę oznacza „poczekaj, aż nikt inny nie ma zamka, więc weź go ”.

Z wysokiego punktu widzenia istnieją dwa główne sposoby implementacji blokad: blokady spinowe i warunki. W przypadku spinlocków zabranie blokady oznacza po prostu „wirowanie” (tzn. Nie robienie nic w pętli), dopóki nikt inny nie będzie miał blokady. W pewnych warunkach, jeśli zadanie próbuje przejąć blokadę, ale jest zablokowane, ponieważ inne zadanie ją przechowuje, nowicjusz wchodzi do kolejki oczekiwania; operacja zwolnienia sygnalizuje każdemu oczekującemu zadaniu, że blokada jest już dostępna.

(Te wyjaśnienia nie są wystarczające, aby wdrożyć blokadę, ponieważ nie mówiłem nic o atomowości. Ale atomowość nie jest tutaj ważna.)

Spinlocki są oczywiście marnotrawstwem: zadanie oczekiwania sprawdza, czy blokada jest zajęta. Dlaczego i kiedy jest używany? Spinlocki są często bardzo tanie w przypadku, gdy zamek nie jest trzymany. Dzięki temu jest atrakcyjny, gdy szansa na zablokowanie zamka jest niewielka. Co więcej, blokady spinowe są opłacalne tylko wtedy, gdy nie oczekuje się, że uzyskanie blokady zajmie dużo czasu. Blokady spinowe są zwykle używane w sytuacjach, w których będą trzymane przez bardzo krótki czas, dzięki czemu większość prób zakończy się sukcesem przy pierwszej próbie, a te, które wymagają oczekiwania, nie czekają długo.

Istnieje dobre wytłumaczenie blokad i innych mechanizmów współbieżności jądra Linux w Sterownikach urządzeń Linux , rozdział 5.


Jaki byłby dobry sposób na wdrożenie innych operacji podstawowych synchronizacji? Weź blokadę, sprawdź, czy ktoś ma zaimplementowaną rzeczywistą operację podstawową, a następnie skorzystaj z harmonogramu lub udziel dostępu? Czy moglibyśmy uznać blok synchronizowany () w Javie za formę blokady, a we właściwie zaimplementowanych prymitywach wystarczy użyć blokady?
Paul Stelian

@PaulStelian Rzeczywiście często stosuje się w ten sposób „wolne” blokady. Nie znam wystarczającej ilości Javy, aby odpowiedzieć na tę część, ale wątpię, synchronizedaby został zaimplementowany przez synchronizedblokadę : blok mógłby działać bardzo długo. synchronizedjest konstrukcją językową ułatwiającą korzystanie z blokad w niektórych przypadkach, a nie prymitywną do budowania większych operacji podstawowych synchronizacji.
Gilles „SO- przestań być zły”

3

Blokada jest blokadą, która działa poprzez wyłączenie harmonogramu i ewentualnie przerywa (wariant irqsave) na tym konkretnym rdzeniu, na którym blokada została nabyta. Różni się od mutexa tym, że wyłącza planowanie, więc tylko twój wątek może działać, gdy spinlock jest trzymany. Muteks pozwala na planowanie innych wątków o wyższym priorytecie, gdy jest on trzymany, ale nie pozwala im na jednoczesne wykonywanie chronionej sekcji. Ponieważ blokady blokują wyłączanie wielozadaniowości, nie można pobrać blokady, a następnie wywołać innego kodu, który będzie próbował uzyskać muteks. Twój kod wewnątrz sekcji blokady nie może nigdy spać (kod zwykle śpi, gdy napotka zablokowany muteks lub pusty semafor).

Inną różnicą w przypadku muteksu jest to, że wątki zwykle ustawiają się w kolejce dla muteksu, więc muteks pod spodem ma kolejkę. Natomiast spinlock zapewnia, że ​​żaden inny wątek nie będzie działał, nawet jeśli będzie musiał. Dlatego nigdy nie wolno blokować podczas wywoływania funkcji spoza pliku, co do których nie masz pewności, że nie będzie spać.

Jeśli chcesz podzielić blokadę z przerwaniem, musisz użyć wariantu irqsave. To nie tylko wyłączy harmonogram, ale także wyłączy przerwania. To ma sens, prawda? Spinlock działa, upewniając się, że nic więcej nie będzie działać. Jeśli nie chcesz, aby przerwanie było uruchamiane, wyłącz je i przejdź bezpiecznie do sekcji krytycznej.

Na maszynie wielordzeniowej spinlock rzeczywiście się obraca, czekając na kolejny rdzeń, który trzyma zamek, aby go zwolnić. To wirowanie odbywa się tylko na maszynach wielordzeniowych, ponieważ na komputerach z jednym rdzeniem nie może się tak zdarzyć (albo przytrzymujesz spinlock i kontynuujesz, albo nigdy nie biegniesz, dopóki blokada nie zostanie zwolniona).

Spinlock nie jest marnotrawstwem tam, gdzie ma to sens. W przypadku bardzo małych sekcji krytycznych niepotrzebne byłoby przydzielanie kolejki zadań mutex w porównaniu do zwykłego zawieszenia harmonogramu na kilka mikrosekund potrzebnych do zakończenia ważnej pracy. Jeśli musisz spać lub przytrzymać blokadę podczas operacji io (która może spać), użyj mutex. Z pewnością nigdy nie blokuj blokady, a następnie spróbuj zwolnić ją w przerwie. Chociaż to zadziała, będzie to jak arduino bzdura while (flagnotset); w takim przypadku użyj semafora.

Złap blokadę, gdy potrzebujesz prostego wzajemnego wykluczenia bloków transakcji pamięciowych. Chwyć muteks, gdy chcesz zatrzymać wiele wątków tuż przed blokadą muteksu, a następnie wybierz wątek o najwyższym priorytecie, aby kontynuować, gdy muteks stanie się wolny i kiedy zablokujesz i zwolnisz w tym samym wątku. Chwyć semafor, jeśli zamierzasz opublikować go w jednym wątku lub przerwie i weź go w innym wątku. Są trzy nieco inne sposoby zapewnienia wzajemnego wykluczenia i są one wykorzystywane do nieco innych celów.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.