Uzyskaj wyłączną blokadę odczytu / zapisu w pliku dla aktualizacji atomowych

10

Chcę mieć plik używany jako licznik. Użytkownik A zapisze i zwiększy ten numer, podczas gdy użytkownik B poprosi o odczytanie pliku. Czy to możliwe, że użytkownik A może zablokować ten plik, aby nikt nie mógł go odczytać ani zapisać, dopóki użytkownik A nie zakończy zapisu?

Przyjrzałem się temu, flockale wydaje mi się, że nie mogę go uruchomić tak, jak się tego spodziewam.

flock -x -w 5 /dev/shm/counter.txt echo "4" >  /dev/shm/counter.txt && sleep 5

Jeśli istnieje bardziej odpowiedni sposób na zdobycie tego podobnego do atomu pliku inkrementacyjnego, to też byłby świetny do usłyszenia!

Mój cel to:

LOCK counter.txt; write to counter.txt;

podczas gdy w tym samym czasie

Read counter.txt; realize it's locked so wait until that lock is finished.
d -_- b
źródło
1
„Wydaje się, że nie działa tak, jak tego oczekuję”. Co to konkretnie oznacza?
John1024,
Jestem pewien, że używam go niepoprawnie, ale korzystając z powyższego kodu, mogę użyć dwóch powłok i umożliwić im edycję pliku licznika, podczas gdy myślałem, że jedna go blokuje. Więc jeśli uruchomię tę linię dwa razy na dwóch osobnych powłokach (każda z własnym numerem do echa), nadal widzę, że zapisywana jest druga liczba
d -_- b
1
Gdy pierwszy ukończy i zwolni blokadę, drugi uruchomi się. Czy to nie tak powinno działać? (W powyższym kodzie && sleep 5jest wykonywany po zwolnieniu blokady przez stado).
John1024,
Hmm, intersting ... W takim razie byłoby to zbyt szybkie, by moje ludzkie oko mogło je złapać. Świetny! Moje następne wyzwanie polega na tym, jak wprowadzić wiele poleceń flock, ale postawię to jako osobne pytanie. Dzięki, John!
d -_- b
3
@d -_- b Kocham twoją nazwę użytkownika. To NAJBARDZIEJ sprytna nazwa użytkownika, jaką kiedykolwiek widziałem.
Devyn Collier Johnson

Odpowiedzi:

10

Przetwarzanie przez Bash poniższego polecenia może być zaskakujące:

flock -x -w 5 /dev/shm/counter.txt echo "4" >  /dev/shm/counter.txt && sleep 5

Najpierw uruchamia się Bash, flock -x -w 5 /dev/shm/counter.txt echo "4" > /dev/shm/counter.txta jeśli zakończy się ono pomyślnie (zwolnienie blokady), to działa sleep 5. Dlatego blokada nie jest utrzymywana przez 5 sekund, których można oczekiwać.

Na bok &kontra&&

Jeśli jeden ma dwa polecenia, Aa Bnastępnie:

  1. A & Bzaczyna się Aw tle, a następnie zaczyna Bbez oczekiwania na Azakończenie.

  2. A && Buruchamia się A, czeka na zakończenie, a następnie, jeśli zakończy się pomyślnie (kod wyjścia 0), rozpoczyna się B. Jeśli się Anie powiedzie (niezerowy kod wyjścia), Bto nigdy nie zostanie uruchomiony.

W sumie, &i &&są dwie zupełnie różne operatory list.

John1024
źródło
3
to zdziwiłbym się, gdyby w A && B, Aby czekać Bdo końca.
Andras Gyomrey
1
w A&& B A jest wykonywane jako pierwsze. B jest wykonywany tylko wtedy, gdy A został pomyślnie wykonany i zakończony. Użyć; B, aby zawsze wykonać B, niezależnie od statusu wykonania A.
kapad
15

Blokady plików nie są obowiązkowe 1 - tzn. Nie można zablokować pliku, aby inny proces nie mógł uzyskać do niego dostępu. Zablokowanie środków plików, jeśli A (kolizyjnego) Proces kontroli aby sprawdzić, czy został on zablokowany, będzie wiedział.

Celem tego flockjest robienie rzeczy takich, jak chcesz, ale musisz używać ich flockprzy każdej próbie dostępu . Pamiętaj, że blokują połączenia; z man flock:

jeśli zamek nie może zostać natychmiast uzyskany, stado czeka, aż zamek będzie dostępny


1. Co sprawia, że ​​funkcja wydaje się bezużyteczna, jeśli używasz jej np. Do bezpieczeństwa, ale nie jest to celem blokad plików - służą one do synchronizacji, czyli tego, co robisz. Użytkownik Leo zwrócił uwagę, że może istnieć niestandardowa implementacja obowiązkowego blokowania plików w jądrze systemu Linux ( patrz ta dyskusja ), w oparciu o historyczne podobieństwa z innych systemów operacyjnych * nix. Wygląda to jednak tylko na interfejs poziomu C.

Złotowłosa
źródło
Dzięki! Pomaga to zrozumieć aspekt „doradczy” i sposób, w jaki muszę go używać za flockkażdym razem. bardzo pomocny!
d -_- b
2

Możesz użyć polecenia „sh -c command ...”, aby uruchomić całe polecenie powłoki, w tym przekierowanie pliku, z blokadą. Ponieważ używasz pliku jako licznika, musisz stale blokować blokadę podczas odczytu i zapisu. Więc chciałbyś zrobić coś takiego, aby zwiększyć licznik i zwrócić jego nową wartość:

flock --exclusive --wait 5 /dev/shm/counter.txt sh -c 'read count < /dev/shm/counter.txt ; echo $((count + 1)) > /dev/shm/counter.txt ; echo $((count + 1))'

Zmiana znaku plus na znak minus powinna zmniejszyć licznik:

flock --exclusive --wait 5 /dev/shm/counter.txt sh -c 'read count < /dev/shm/counter.txt ; echo $((count - 1)) > /dev/shm/counter.txt ; echo $((count - 1))'

Oczekuję, że zainicjujesz licznik, zanim zdarzy się jakakolwiek rywalizacja, więc nie musisz się martwić o tak wczesne zablokowanie:

echo 0 > /dev/shm/counter.txt

Nie sądzę, żebyś kiedykolwiek musiał blokować wartość licznika, podczas gdy mogłaby wystąpić sprzeczka, ale jeśli kiedykolwiek to zrobiłeś, powinieneś to zrobić w ten sposób:

flock --exclusive --wait 5 /dev/shm/counter.txt sh -c 'echo 0 > /dev/shm/counter.txt'

Myślę, że rozumiesz, jak zrobić czytanie, ale dołączam to dla kompletności:

flock --shared /dev/shm/counter.txt cat /dev/shm/counter.txt
Adam Richter
źródło
To wydaje się być jedyną odpowiedzią, która poprawnie zauważa, że ​​w pytaniu plik jest otwierany przez powłokę, zanim stado nawet uruchomi się ...
eichin