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?
Odpowiedzi:
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\n
poprzez5\n
z jednej sekundowym opóźnieniem pomiędzy każdym i dwóch instancji jest uruchomiona 2,5 sekundy później dostaniesz to:Aby odpowiedzieć na twoje pytanie: Nie.
źródło
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 piszehello
i tylko wtedy instancja 2 piszebar
, wtedy plik będzie zawierałfoohellobar
.Proces skutecznie zapisuje do pliku, gdy wywołuje
write
wywołanie systemowe. Wywołanie towrite
jest atomowe: każde wywołaniewrite
zapisuje sekwencję bajtów, która nie zostanie przerwana przez inne programy. Często istnieje ograniczenie ilości danych,write
które efektywnie zapisuje pojedyncze połączenie : w przypadku większych rozmiarów zapisywany jest tylko początek danych, a aplikacja musi wywołaćwrite
ponownie. 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.źródło