Czy przekierowanie wyjścia do pliku powoduje zablokowanie pliku?

30

Jeśli mam polecenie

$ ./script >> file.log

która jest wywoływana dwukrotnie, przy czym drugie połączenie występuje przed zakończeniem pierwszego, co się dzieje?

Czy pierwsze wywołanie ma wyłączną blokadę pliku wyjściowego? Jeśli tak, to czy drugi skrypt kończy się niepowodzeniem podczas próby zapisu, czy też powłoka akceptuje dane wyjściowe (pozwalając na zakończenie skryptu) i zgłasza błąd?

Czy plik dziennika jest zapisywany dwukrotnie?


źródło
1
Nie znam żadnego systemu, który domyślnie blokowałby plik. Bardziej prawdopodobne jest, że oba programy przeplatają swoje zapisy, ponieważ oba byłyby w trybie dołączania. Wyniki byłyby raczej nieprzewidywalne. Zamiast „witaj świecie” możesz dostać „hweolrllod”.
jw013

Odpowiedzi:

18

Ponieważ używasz >>, co oznacza dołączanie, każdy wiersz danych wyjściowych z każdej instancji zostanie dodany w kolejności, w jakiej wystąpił.

Jeśli wydruki wyjściowe skryptu 1\npoprzez 5\nz jednej sekundowym opóźnieniem pomiędzy każdym i dwóch instancji jest uruchomiona 2,5 sekundy później dostaniesz to:

1
2
1
3
2
4
3
5
4
5

Aby odpowiedzieć na twoje pytanie: Nie.

bahamat
źródło
23

Systemy uniksowe w zasadzie unikają obowiązkowych blokad. Istnieje kilka przypadków, w których jądro zablokuje plik przed modyfikacjami dokonanymi przez programy użytkownika, ale nie, jeśli jest on po prostu zapisywany przez inny program. Żaden system uniksowy nie zablokuje pliku, ponieważ program do niego pisze.

Jeśli chcesz, aby współbieżne wystąpienia skryptu nie stąpały po sobie, musisz użyć jawnego mechanizmu blokującego, takiego jak .flock lockfile

Po otwarciu pliku do dołączenia, co się >>dzieje, każdy program ma pewność, że zawsze zapisuje na końcu pliku. Dane wyjściowe wielu instancji nigdy się nie zastąpią, a jeśli naprzemiennie będą zapisywać, ich dane wyjściowe będą w tej samej kolejności co zapisy.

Złą rzeczą, która może się zdarzyć, jest to, że jeden z przykładów napisze kilka fragmentów danych wyjściowych i spodziewa się, że wyjdą razem. Pomiędzy kolejnymi zapisami według jednej instancji, inne instancje mogą wykonywać własne zapisy. Na przykład, jeśli instancja 1 pisze foo, to instancja 2 pisze helloi tylko wtedy instancja 2 pisze bar, wtedy plik będzie zawierał foohellobar.

Proces skutecznie zapisuje do pliku, gdy wywołuje writewywołanie systemowe. Wywołanie to writejest atomowe: każde wywołanie writezapisuje sekwencję bajtów, która nie zostanie przerwana przez inne programy. Często istnieje ograniczenie ilości danych, writektóre efektywnie zapisuje pojedyncze połączenie : w przypadku większych rozmiarów zapisywany jest tylko początek danych, a aplikacja musi wywołać writeponownie. Ponadto wiele programów wykonuje buforowanie: gromadzą dane w obszarze pamięci, a następnie zapisują je w jednym kawałku. Niektóre programy opróżniają bufor wyjściowy po pełnym wierszu lub innej znaczącej separacji. Dzięki takim programom można oczekiwać nieprzerwanych całych linii, o ile nie są one zbyt długie (do kilku kilobajtów; zależy to od systemu operacyjnego). Jeśli program nie opróżnia się w znaczących miejscach, ale tylko w oparciu o rozmiar bufora, możesz zobaczyć coś takiego jak 4kB z jednej instancji, następnie 4kB z innej instancji, następnie ponownie 4kB z pierwszej instancji i tak dalej.

Gilles „SO- przestań być zły”
źródło