Ketika saya mengarahkan output perintah ke file (misalnya, echo Hello > file
) akankah file itu dijamin memiliki data seperti itu setelah perintah keluar? Atau masih ada jendela yang sangat kecil antara perintah keluar dan data yang ditulis ke file? Saya ingin membaca file tepat setelah perintah keluar, tetapi saya tidak ingin membaca file kosong.
linux
hard-drive
process
file-io
Eric
sumber
sumber
echo
dan>
bukan proses yang terpisah (berumur pendek)? Dan di mana outputecho
tetap sebelum>
dieksekusi?>
adalah pengalihan shell. Itu sama seperti jika program telah membuka file bernama untuk menulis dan mengganti stdout dengan itu yang persis seperti yang dilakukan shell.file
mengandungHello
terlepas dari apakah itu memerah atau tidak.Jawaban:
Ada beberapa lapisan buffer / cache yang terlibat.
Cache CPU.
Data disatukan byte demi byte, dan disimpan dalam cache CPU. Jika cache CPU penuh dan data belum diakses untuk sementara waktu, blok yang berisi data kami dapat ditulis ke memori utama. Ini, sebagian besar, disembunyikan dari pemrogram aplikasi.
Buffer dalam proses.
Ada beberapa memori yang disisihkan dalam proses pengumpulan data sehingga kita perlu sesedikit mungkin meminta OS, karena itu relatif mahal. Proses menyalin data ke buffer ini, yang sekali lagi dapat didukung oleh cache CPU, sehingga tidak ada jaminan bahwa data akan disalin ke memori utama. Aplikasi perlu menyiram buffer ini secara eksplisit, misalnya menggunakan fclose (3) atau fsync (3). Fungsi exit (3) juga melakukan ini sebelum proses diakhiri, sedangkan fungsi _exit (2) tidak , yang mengapa ada peringatan besar di halaman manual untuk fungsi memanggilnya hanya jika Anda tahu apa yang Anda lakukan. perbuatan.
Kernel buffer
OS kemudian menyimpan cache sendiri, untuk meminimalkan jumlah permintaan yang perlu dikirim ke disk. Tembolok ini bukan milik proses tertentu, jadi data di sana mungkin milik proses yang telah selesai, dan karena semua akses masuk ke sini, program selanjutnya akan melihat data jika telah mencapai di sini. Kernel akan menulis data ini ke disk ketika ada waktu untuk melakukannya atau ketika ditanya secara eksplisit.
Cache drive
Disk drive itu sendiri juga menyimpan cache untuk mempercepat akses. Ini ditulis dengan cukup cepat, dan ada perintah untuk menulis data yang tersisa di cache dan melaporkan ketika itu selesai, yang menggunakan OS pada shutdown untuk memastikan tidak ada data yang tersisa yang tidak tertulis sebelum mematikan.
Untuk aplikasi Anda, itu sudah cukup bagi data untuk didaftarkan di buffer kernel (data aktual mungkin masih hidup dalam cache CPU pada saat ini, dan mungkin belum ditulis ke memori utama): proses "echo" berakhir, yang berarti bahwa setiap buffer dalam proses pasti telah memerah dan data diserahkan ke OS, dan ketika Anda memulai proses baru, dijamin bahwa OS akan memberikan data yang sama saat diminta.
sumber
Jika aplikasi tidak memiliki cache internal, maka perubahan akan segera ditulis ke file. Sama untuk contoh Anda. File tersebut adalah entitas logis dalam memori yang akan segera diperbarui. Setiap operasi selanjutnya pada file akan melihat perubahan yang dilakukan oleh program.
Namun , ini tidak berarti perubahan ditulis ke disk fisik. Perubahan mungkin berlama-lama di dalam cache sistem file OS atau cache perangkat keras. Untuk membersihkan buffer sistem file, gunakan
sync
perintah.Anda seharusnya tidak mengalami masalah praktis di sini.
sumber
exit
tidak setidaknya disebut secara implisit). Perpustakaan / bahasa lain (mis. Java!) Memberikan lebih sedikit jaminan.Secara umum jawabannya tidak .
Itu tergantung pada perintah. Seperti jawaban lain menyebutkan, jika perintah tidak secara internal buffer data, semua data akan tersedia ketika perintah berakhir.
Tetapi sebagian besar, jika tidak semua, perpustakaan I / O standar melakukan buffer stdout secara default (sampai batas tertentu), dan memberikan jaminan yang berbeda tentang penyiraman otomatis buffer ketika aplikasi ditutup.
C menjamin bahwa jalan keluar yang normal akan mengguyur buffer . "Keluar normal" berarti yang
exit
disebut - baik secara eksplisit, atau dengan kembali darimain
. Namun, jalan keluar yang abnormal dapat menghindari panggilan ini (dan karenanya meninggalkan buffer yang tidak terhalang).Berikut ini contoh sederhana:
Jika Anda mengkompilasi ini dan melaksanakannya,
test
akan tidak selalu ditulis ke stdout.Bahasa pemrograman lain bahkan memberikan jaminan lebih sedikit: Java, misalnya, tidak otomatis dihapus pada saat penghentian program . Jika buffer output berisi garis yang tidak ditentukan, maka mungkin akan hilang, kecuali
System.out.flush()
disebut secara eksplisit.Yang mengatakan, badan pertanyaan Anda menanyakan sesuatu yang sedikit berbeda: jika data masuk dalam file sama sekali , itu harus segera dilakukan setelah perintah berakhir (tunduk pada peringatan yang dijelaskan dalam jawaban lain).
sumber
write()
atau apa punpwrite()
akan terjadi sebelum proses keluar, dan saat itulah perubahan file menjadi terlihat. Jadi perubahan file terakhir pasti sebelum proses penghentian, segera-sebelum paling lambat. Saya pikir bahkan dengan sebuahmmap(MAP_SHARED)
file, tidak ada cara untuk mengamati proses pemutusan terjadi sebelum semua perubahan file yang akan terjadi.Saya pikir tidak ada pertanyaan yang cukup untuk mengatasi masalah ini:
Seperti jawaban lain menjelaskan, program berperilaku baik flush buffer file internal sebelum proses berakhir secara normal . Setelah itu, data mungkin masih ada di buffer kernel atau perangkat keras sebelum ditulis ke penyimpanan persisten. Namun , semantik sistem file Linux menjamin bahwa semua proses melihat konten file dengan cara yang sama seperti kernel termasuk buffer internal 1 .
Ini biasanya diterapkan dengan memiliki paling banyak satu buffer in-kernel per objek file dan meminta semua akses file untuk melewati buffer ini.
Jika suatu proses membaca file, kernel akan menyajikan konten buffer ke proses, jika bagian file yang diminta saat ini dalam buffer; jika tidak, kernel akan mengambil data dari media penyimpanan yang mendasarinya dan menempatkannya di dalam buffer, kemudian kembali ke langkah sebelumnya.
Jika suatu proses menulis ke suatu file, data pertama-tama ditempatkan di dalam buffer in-kernel untuk file itu. Akhirnya konten buffer akan dibuang ke penyimpanan. Sementara itu, akses baca dipenuhi dari buffer yang sama (lihat di atas).
1 Setidaknya untuk file, direktori, dan tautan simbolik biasa. FIFO dan soket adalah masalah yang berbeda karena kontennya tidak pernah disimpan secara tetap. Ada beberapa kasus khusus file biasa yang isinya bergantung pada siapa yang bertanya; contohnya adalah file dalam procfs dan sysfs (pikirkan
/proc/self
yang merupakan tautan simbolis ke ID proses dari proses membaca tautan simbolis).sumber
mmap()
dan O_DIRECT, yang dapat menyebabkan hal-hal yang tidak sinkron antara disk dan cache halaman (tetapi itu akan menyelesaikan saat proses yang keluar itu dilakukan).Dengan anggapan perintah Anda dijalankan oleh beberapa program menggunakan pustaka runtime C, pada titik tertentu harus dijalankan
fclose
untuk menutup file yang terbuka.Halaman manual untuk
fclose
fungsi C mengatakan:dan halaman manual untuk
fflush
memiliki catatan yang sama. Halaman manual untukclose
mengatakan:Perhatikan bahwa data tersedia untuk proses lain meskipun tidak disinkronkan ke drive. Mungkin itu sudah cukup baik untukmu.
Jika Anda ragu, tulis tes.
sumber
close()
syscall untuk menutup deskriptor file.close
file sebelum keluar (dalam program Hacky yang tidak memeriksa kesalahan); kernel akan membersihkannya, memanggilclose
Anda secara efektif setelah proses Anda mati. Namun, Anda perlu melakukanfclose
stdio stream yang disangga, atau membiarkan libc melakukan itu untuk Andaexit(3)
, sebagai lawan dari panggilan sistem keluar secara langsung.Iya nih. Shell membuka file output, dan
echo
output langsung ke sana. Setelah perintah keluar, selesai.Apakah data sudah ada di media adalah masalah lain, yang hanya penting jika ada kegagalan perangkat keras, atau Anda memeriksa partisi langsung dengan beberapa perangkat lunak forensik, melewati sistem file yang dipasang.
Jangan khawatir, kernel hanya menyimpan satu tampilan file, terlepas dari seberapa sering dibuka.
sumber
mmap(MAP_SHARED)
: menyimpan ke dalam wilayah mmaped tidak koheren dengan pembacaan file (oleh utas itu atau proses lainnya). Inilah sebabnya mengapamsync(2)
ada. Setidaknya itulah yang diperingatkan halaman manual; tergantung pada implementasinya, Linux sebenarnya dapat memetakan halaman fisik dari pagecache, dalam hal ini saya kira itu pada dasarnya adalah koheren (modulo memory-order). Bagaimanapun, itu semua masih terjadi sebelumnya_exit(2)
.Sebagai aturan umum, setiap data yang dimiliki oleh kernel dipelihara & dibersihkan oleh kernel, titik. Data tersebut termasuk data yang ditransfer ke memori kernel dengan panggilan sistem seperti
write(2)
.Namun, jika aplikasi Anda (mis. C library) melakukan buffering di atas ini, maka kernel jelas tidak tahu dan karenanya tidak menjamin pembersihannya.
Selain itu, saya tidak percaya ada jaminan waktu untuk pembersihan — itu, pada umumnya, dilakukan atas dasar "upaya terbaik" (baca: "ketika saya punya waktu").
sumber
waitpid()
kembali, jika pembersihan sama sekali terjadi. yaitu proses lain tidak dapat secara langsung mengamati penghentian proses yang terjadi sebelum modifikasi file dilakukan oleh proses itu. (Saya mengatakan "langsung" untuk mengesampingkan pengamatan tidak langsung melalui stempel waktu file NFS, karena caching NFS tidak sepenuhnya koheren di antara host.)fsync
/fdatasync
, meskipun buffer-write-back di Linux akan mulai setelah/proc/sys/vm/dirty_writeback_centisecs
seperseratus detik (jika tidak ditunda oleh lalu lintas I / O lainnya), dan berbagai merdu lain dalam direktori procfs juga mempengaruhi hal-hal (misalnya bagaimana besar untuk membiarkan buffer tumbuh sebelum melakukan balasan apa pun).Tidak, tidak ada.
Anda dapat membaca konten final file tepat setelah perintah keluar, Anda tidak akan pernah membaca file yang kosong. (Di C dan C ++, gunakan sistem panggilan wait , waitpid , wait3 atau wait4 untuk menunggu program keluar, dan baru kemudian membaca file. Jika Anda menggunakan shell, bahasa pemrograman lain atau pustaka (mis. Perpustakaan C sistem panggilan atau kelas Proses Java ), mungkin sudah menggunakan salah satu dari panggilan sistem ini.)
Seperti yang telah ditunjukkan oleh jawaban dan komentar lainnya, Anda mungkin pada akhirnya membaca file kosong setelah keluar dari program jika program telah keluar tanpa menyiram buffer output internal (mis. Karena _exit , batalkan , atau menerima sinyal fatal, atau karena itu program Java keluar secara normal). Namun tidak ada yang dapat Anda lakukan mengenai hal ini pada saat ini: data yang tidak terhapus hilang selamanya, menunggu tambahan tidak akan memulihkannya.
sumber
iya nih
Maaf karena mungkin menambahkan jawaban yang berlebihan, tetapi sebagian besar tampaknya berfokus pada herring merah pada judul pertanyaan. Tapi sejauh yang saya tahu, pertanyaannya bukan tentang buffering sama sekali, tetapi ini:
Ya tanpa syarat. Penggunaan ">" yang Anda gambarkan, bersama dengan "|" dan "<", adalah model pemrosesan berbasis pipa yang menjadi dasar dunia Unix dan Linux. Anda akan menemukan ratusan, jika tidak ribuan skrip benar-benar tergantung pada perilaku ini di setiap instalasi Linux.
Ini berfungsi seperti yang Anda inginkan per desain, dan jika ada peluang sekecil apa pun dari kondisi balapan, mungkin sudah diperbaiki beberapa dekade yang lalu.
sumber