Kiedy przekieruję wyjście polecenia do pliku (np. echo Hello > file
), Czy plik ten będzie miał gwarancję, że będzie miał takie dane zaraz po wyjściu polecenia? Czy jest jeszcze bardzo małe okno między wyjściami polecenia a danymi zapisanymi w pliku? Chciałbym przeczytać plik zaraz po wyjściu polecenia, ale nie chcę czytać pustego pliku.
linux
hard-drive
process
file-io
Eric
źródło
źródło
echo
i>
nie oddzielne (krótko) procesy? A gdzie wykonywany jest wynikecho
pozostania przed>
?>
to przekierowanie powłoki. Jest tak, jakby program otworzył nazwany plik do zapisu i zastąpił go stdout, co jest dokładnie tym, co robi powłoka.file
zawartościHello
bez względu na to, czy jest ona opróżniona czy nie.Odpowiedzi:
W grę wchodzi wiele warstw buforów / pamięci podręcznych.
Pamięć podręczna procesora.
Dane są łączone bajt po bajcie i przechowywane w pamięci podręcznej procesora. Jeśli pamięć podręczna procesora jest pełna i dane nie były dostępne przez pewien czas, blok zawierający nasze dane może zostać zapisany w pamięci głównej. Są one w większości ukryte przed programistami aplikacji.
Bufory procesowe.
W procesie, w którym gromadzone są dane, jest trochę pamięci, dlatego musimy składać jak najmniej żądań do systemu operacyjnego, ponieważ jest to stosunkowo kosztowne. Proces kopiuje dane do tych buforów, które ponownie mogą być wspierane przez pamięci podręczne procesora, więc nie ma gwarancji, że dane zostaną skopiowane do pamięci głównej. Aplikacja musi jawnie opróżnić te bufory, na przykład używając fclose (3) lub fsync (3). Funkcja exit (3) robi to również przed zakończeniem procesu, podczas gdy funkcja _exit (2) nie , dlatego na stronie podręcznika jest duże ostrzeżenie, aby ta funkcja mogła ją wywołać tylko wtedy, gdy wiesz, kim jesteś robić.
Bufory jądra
System operacyjny utrzymuje następnie własną pamięć podręczną, aby zminimalizować liczbę żądań, które musi wysłać na dyski. Ta pamięć podręczna nie należy w szczególności do żadnego procesu, więc dane w niej mogą należeć do procesów, które już się zakończyły, a ponieważ wszystkie przejścia przechodzą tutaj, następny program zobaczy dane, jeśli tutaj dotarł. Jądro zapisze te dane na dyskach, gdy będzie miał na to czas lub gdy zostanie wyraźnie o to poproszony.
Pamięć podręczna dysku
Same dyski przechowują również pamięć podręczną, aby przyspieszyć dostęp. Są one pisane dość szybko i istnieje polecenie, aby zapisać pozostałe dane w pamięci podręcznej i zgłosić, kiedy jest to zakończone, którego system operacyjny używa podczas zamykania, aby upewnić się, że żadne dane nie zostaną niepisane przed wyłączeniem.
W przypadku aplikacji wystarczy, aby dane zostały zarejestrowane w buforach jądra (rzeczywiste dane mogą w tym momencie nadal znajdować się w pamięci podręcznej procesora i mogły nie zostać zapisane w pamięci głównej): proces „echo” kończy się, co oznacza, że wszelkie bufory wewnątrzprocesowe musiały zostać opróżnione, a dane przekazane do systemu operacyjnego, a po rozpoczęciu nowego procesu gwarantuje się, że system operacyjny zwróci te same dane, gdy zostanie o to poproszony.
źródło
Jeśli aplikacja nie ma żadnych wewnętrznych pamięci podręcznych, zmiany zostaną natychmiast zapisane w pliku. To samo dla twojego przykładu. Plik jest logicznym bytem w pamięci, który zostanie natychmiast zaktualizowany. Wszelkie dalsze operacje na pliku spowodują zmiany dokonane przez program.
Nie oznacza to jednak , że zmiana została zapisana na dysku fizycznym. Zmiany mogą pozostać w pamięci podręcznej systemu plików OS lub pamięci podręcznej sprzętu. Aby opróżnić bufory systemu plików, użyj
sync
polecenia.Nie powinieneś mieć tutaj żadnych praktycznych problemów.
źródło
exit
nie zostanie przynajmniej domyślnie wywołany). Inne biblioteki / języki (np. Java!) Dają mniej gwarancji.Ogólnie odpowiedź brzmi „ nie” .
To zależy od polecenia. Jak wspomniano w innych odpowiedziach, jeśli polecenie nie buforuje danych wewnętrznie, wszystkie dane będą dostępne po zakończeniu polecenia.
Ale większość, jeśli nie wszystkie, standardowe biblioteki we / wy domyślnie wykonują buforowanie standardowe (do pewnego stopnia) i dają różne gwarancje dotyczące automatycznego opróżniania buforów po zamknięciu aplikacji.
C gwarantuje, że normalne wyjście opróżni bufory . „Normalne wyjście” oznacza, że
exit
jest wywoływane - albo jawnie, albo przez powrót zmain
. Jednak nienormalne wyjście może obejść to wezwanie (a zatem pozostawić niewyłączone bufory).Oto prosty przykład:
Jeśli to skompilować i uruchomić go,
test
będzie nie muszą być zapisywane na standardowe wyjście.Inne języki programowania dają nawet mniej gwarancje: Java, na przykład, czy nie auto-flush Po wygaśnięciu programu . Jeśli bufor wyjściowy zawiera niezakończoną linię, może zostać utracony, chyba że zostanie
System.out.flush()
jawnie wywołany.To powiedziawszy, twoje pytanie pyta o coś nieco innego: jeśli dane w ogóle dotrą do pliku , powinno to zrobić natychmiast po zakończeniu polecenia (z zastrzeżeniem zastrzeżeń opisanych w innych odpowiedziach).
źródło
write()
lubpwrite()
wywołanie systemowe nastąpi wcześniej wyjść procesowych, a to jest, gdy zmienia plików stają się widoczne. Tak więc ostatnia zmiana pliku jest zdecydowanie przed zakończeniem procesu, najpóźniej bezpośrednio przed. Myślę, że nawet w przypadkummap(MAP_SHARED)
pliku nie ma sposobu, aby zaobserwować zakończenie procesu przed wszystkimi zmianami plików, które mają nastąpić.Myślę, że żadne pytanie nie rozwiązuje jeszcze wystarczająco tej kwestii:
Jak wyjaśniają inne odpowiedzi, dobrze zachowujący się program opróżnia wewnętrzne bufory plików, zanim proces zakończy się normalnie . Następnie dane mogą pozostać w buforze jądra lub sprzętu, zanim zostaną zapisane w pamięci trwałej. Jednak semantyka systemu plików w systemie Linux gwarantuje, że wszystkie procesy widzą zawartość plików w taki sam sposób, jak jądro, w tym bufory wewnętrzne 1 .
Zwykle jest to realizowane przez posiadanie co najwyżej jednego bufora jądra na obiekt pliku i wymaganie pełnego dostępu do pliku, aby przejść przez ten bufor.
Jeśli proces odczyta plik, jądro przedstawi zawartość bufora procesowi, jeśli żądana część pliku znajduje się obecnie w buforze; jeśli nie jest, jądro pobierze dane z podstawowego nośnika pamięci i umieści je w buforze, a następnie wróci do poprzedniego kroku.
Jeśli proces zapisuje do pliku, dane są najpierw umieszczane w buforze jądra dla tego pliku. Ostatecznie zawartość bufora zostanie opróżniona do pamięci. Tymczasem dostęp do odczytu jest zapewniony z tego samego bufora (patrz wyżej).
1 Przynajmniej dla zwykłych plików, katalogów i dowiązań symbolicznych. FIFO i gniazda to inna sprawa, ponieważ ich zawartość i tak nigdy nie jest przechowywana w sposób trwały. Istnieją pewne szczególne przypadki zwykłych plików, których zawartość zależy od tego, kto pyta; przykładami są pliki w procfs i sysfs (pomyśl,
/proc/self
który jest dowiązaniem symbolicznym do identyfikatora procesu odczytującego dowiązanie symboliczne).źródło
mmap()
O_DIRECT, co może prowadzić do braku synchronizacji między dyskiem a pamięcią podręczną strony (ale to rozwiąże moment, w którym proces się kończy).Zakładając, że twoje polecenie jest wykonywane przez jakiś program korzystający z biblioteki wykonawczej C, w pewnym momencie powinien on wywołać,
fclose
aby zamknąć otwarty plik.Strona podręcznika dla
fclose
funkcji C mówi:a strona podręcznika dla
fflush
ma tę samą notatkę. Stronaclose
podręcznika dla mówi:Pamiętaj, że dane są dostępne dla innych procesów, nawet jeśli nie są zsynchronizowane z dyskiem. Może to już ci wystarczy.
W razie wątpliwości napisz test.
źródło
close()
syscall do zamknięcia deskryptora pliku.close
plików przed zamknięciem (w Hacky programów, które nie sprawdzają błędów); jądro oczyści je, skutecznie wzywającclose
po zakończeniu procesu. Potrzebujesz jednakfclose
buforowanych strumieni stdio lub pozwól libc zrobić to za Ciebieexit(3)
, w przeciwieństwie do bezpośredniego wyjścia systemowego.Tak. Powłoka otwiera plik
echo
wyjściowy i wysyła bezpośrednio do niego. Po wyjściu polecenia jest gotowe.To, czy dane są już na nośniku, to inna sprawa, która ma znaczenie tylko wtedy, gdy wystąpi awaria sprzętowa, lub gdy sprawdzasz partycję na żywo za pomocą jakiegoś oprogramowania kryminalistycznego, omijając zamontowany system plików.
Nie martw się, jądro zachowuje tylko jeden widok pliku, niezależnie od tego, jak często jest otwierany.
źródło
mmap(MAP_SHARED)
: przechowywanie w regionie mmaped nie jest spójne z odczytami pliku (przez ten wątek lub inne procesy). Właśnie dlategomsync(2)
istnieje. Przynajmniej o tym ostrzegają strony podręcznika; w zależności od implementacji, Linux może faktycznie mapować fizyczne strony z pamięci podręcznej, w takim przypadku domyślam się, że jest zasadniczo spójny (modułowe porządkowanie pamięci). Tak czy inaczej, wszystko dzieje się wcześniej_exit(2)
.Zasadniczo wszelkie dane posiadane przez jądro są utrzymywane i usuwane przez jądro, kropka. Takie dane obejmują dane przesyłane do pamięci jądra za pomocą wywołania systemowego, takiego jak
write(2)
.Jednakże, jeśli aplikacja (np C Library) wykonuje buforowanie na szczycie tego, wtedy jądro oczywiście nie ma pojęcia, a tym samym nie gwarantują jego oczyszczenia.
Co więcej, nie sądzę, istnieje jakikolwiek rozrządu gwarancją czystego-up-to jest na ogół wykonywana na zasadzie „best-effort” (czytaj: „kiedy mam sec”) podstawy.
źródło
waitpid()
powrotem procesu nadrzędnego , jeśli w ogóle nastąpi. tzn. inne procesy nie mogą bezpośrednio zaobserwować zakończenia procesu przed jakimikolwiek modyfikacjami pliku dokonanymi przez ten proces. (Powiedziałem „bezpośrednio”, aby wykluczyć pośrednią obserwację za pomocą znaczników czasowych plików NFS, ponieważ buforowanie NFS nie jest idealnie spójne między hostami.)fsync
/fdatasync
, chociaż buforowanie w Linuksie rozpocznie się po/proc/sys/vm/dirty_writeback_centisecs
setnych sekundach (jeśli nie zostanie opóźnione przez inny ruch I / O), a różne inne elementy dostrajające w tym katalogu procfs również wpływają na różne rzeczy (np. Jak duże, aby bufory rosły przed wykonaniem jakiegokolwiek zapisu).Nie, nie ma.
Możesz przeczytać ostateczną zawartość pliku zaraz po wyjściu z polecenia, zamiast tego nigdy nie będziesz czytać pustego pliku. (W C i C ++ użyj wywołań systemowych wait , waitpid , wait3 lub wait4 , aby poczekać na zakończenie programu, a dopiero potem przeczytaj plik. Jeśli używasz powłoki, innego języka programowania lub biblioteki (np. Biblioteki C. system wywołania lub klasa Java Process ), prawdopodobnie używa już jednego z tych wywołań systemowych.)
Jak wskazały inne odpowiedzi i komentarze, możesz skończyć z czytaniem pustego pliku po wyjściu z programu, jeśli program zakończył pracę bez opróżniania wewnętrznych buforów wyjściowych (np. Z powodu wyjścia , przerwania lub odebrania krytycznego sygnału lub ponieważ program Java wychodzący normalnie). Jednak w tej chwili nic nie możesz na to poradzić : nierozpoznane dane zostaną utracone na zawsze, dodatkowe czekanie ich nie odzyska.
źródło
tak
Przepraszamy za dodanie kolejnej zbędnej odpowiedzi, ale większość wydaje się skupiać na czerwonym śledziu tytułu pytania. Ale o ile wiem, pytanie wcale nie dotyczy buforowania, ale to:
Tak, bezwarunkowo. Użycie opisywanego słowa „>” wraz z „|” a „<” to oparty na potokach model przetwarzania, na którym opiera się świat Unix i Linux. W każdej instalacji Linuksa znajdziesz setki, jeśli nie tysiące skryptów całkowicie zależnych od tego zachowania.
Działa tak, jak chcesz według projektu, a jeśli byłaby nawet najmniejsza szansa na wyścig, zostałby naprawiony prawdopodobnie kilkadziesiąt lat temu.
źródło