Saya tidak membeli jawaban yang diterima sebelumnya. SIGPIPE
dihasilkan tepat ketika write
gagal dengan EPIPE
, bukan sebelumnya - pada kenyataannya satu cara aman untuk menghindari SIGPIPE
tanpa mengubah disposisi sinyal global adalah dengan menutupinya sementara dengan pthread_sigmask
, melakukan write
, kemudian melakukan sigtimedwait
(dengan nol batas waktu) untuk mengkonsumsi SIGPIPE
sinyal yang tertunda (yang dikirim ke utas panggilan, bukan proses) sebelum membuka kedoknya lagi.
Saya yakin alasan yang SIGPIPE
ada jauh lebih sederhana: menetapkan perilaku default yang waras untuk program "filter" murni yang terus menerus membaca masukan, mengubahnya, dan menulis keluaran. Tanpa SIGPIPE
, kecuali program ini secara eksplisit menangani kesalahan penulisan dan segera keluar (yang mungkin bukan perilaku yang diinginkan untuk semua kesalahan tulis), program ini akan terus berjalan hingga kehabisan masukan bahkan jika pipa keluarannya telah ditutup. Tentu Anda dapat menduplikasi perilaku SIGPIPE
dengan secara eksplisit memeriksa EPIPE
dan keluar, tetapi tujuan keseluruhan dari SIGPIPE
adalah untuk mencapai perilaku ini secara default saat programmer malas.
write
.Karena program Anda mungkin menunggu I / O atau ditangguhkan. SIGPIPE menginterupsi program Anda secara tidak sinkron, menghentikan panggilan sistem, sehingga dapat ditangani dengan segera.
Memperbarui
Pertimbangkan saluran pipa
A | B | C
.Hanya untuk kepastian, kita akan berasumsi bahwa B adalah loop salinan kanonik:
B
diblokir pada panggilan baca (2) menunggu data dariA
saatC
berakhir. Jika Anda menunggu kode pengembalian dari write (2) , kapan B akan melihatnya? Jawabannya, tentu saja, tidak sampai A menulis lebih banyak data (yang bisa jadi menunggu lama - bagaimana jika A diblokir oleh sesuatu yang lain?). Perhatikan, omong-omong, ini juga memungkinkan kita membuat program yang lebih sederhana dan lebih bersih. Jika Anda bergantung pada kode kesalahan dari menulis, Anda memerlukan sesuatu seperti:Pembaruan lainnya
Aha, kamu bingung dengan perilaku penulisnya. Anda lihat, ketika deskriptor file dengan penulisan tertunda ditutup, SIGPIPE terjadi saat itu juga. Meskipun penulisan akan mengembalikan -1 pada akhirnya , inti dari sinyal ini adalah untuk memberi tahu Anda secara asinkron bahwa penulisan tidak lagi memungkinkan. Ini adalah bagian dari apa yang membuat seluruh struktur pipa rutin yang elegan berfungsi di UNIX.
Sekarang, saya dapat mengarahkan Anda ke seluruh diskusi di salah satu dari beberapa buku pemrograman sistem UNIX, tetapi ada jawaban yang lebih baik: Anda dapat memverifikasi ini sendiri. Menulis
B
program sederhana [1] - Anda sudah punya nyali, yang Anda butuhkan hanyalah amain
dan beberapa termasuk - dan tambahkan penangan sinyal untukSIGPIPE
. Jalankan pipa sepertidan di jendela terminal lain, pasang debugger ke B dan letakkan breakpoint di dalam penangan sinyal B.
Sekarang, bunuh lebih banyak dan B harus istirahat di penangan sinyal Anda. periksa tumpukannya. Anda akan mengetahui bahwa pembacaan masih menunggu keputusan. biarkan penangan sinyal melanjutkan dan kembali, dan melihat hasil yang dikembalikan oleh tulis - yang kemudian akan menjadi -1.
[1] Biasanya, Anda akan menulis program B Anda dalam C. :-)
sumber
SIGPIPE
adalah tidak disampaikan selama membaca, tapi selamawrite
. Anda tidak perlu menulis program C untuk mengujinya, jalankan sajacat | head
, danpkill head
di terminal terpisah. Anda akan melihat bahwacat
dengan senang hati hidup dalam menungguread()
—hanya ketika Anda mengetik sesuatu dan menekan enter yangcat
mati dengan pipa yang rusak, persis karena mencoba menulis keluaran.SIGPIPE
tidak dapat dikirim keB
saatB
diblokirread
karenaSIGPIPE
tidak dibuat hinggaB
upayawrite
. Tidak ada utas yang "menunggu I / O atau ditangguhkan" saat meneleponwrite
pada waktu yang sama.SIGPIPE
dibesarkan saat diblokir diread
? Saya tidak dapat mereproduksi perilaku itu sama sekali (dan saya tidak benar-benar yakin mengapa saya menerima ini di tempat pertama)https://www.gnu.org/software/libc/manual/html_mono/libc.html
Tautan ini mengatakan:
Pipa atau FIFO harus dibuka di kedua ujungnya secara bersamaan. Jika Anda membaca dari pipa atau file FIFO yang tidak memiliki proses menulis padanya (mungkin karena mereka semua telah menutup file, atau keluar), pembacaan mengembalikan akhir file. Menulis ke pipa atau FIFO yang tidak memiliki proses pembacaan dianggap sebagai kondisi kesalahan; itu menghasilkan sinyal SIGPIPE, dan gagal dengan kode kesalahan EPIPE jika sinyal ditangani atau diblokir.
- Makro: int SIGPIPE
Pipa rusak. Jika Anda menggunakan pipa atau FIFO, Anda harus mendesain aplikasi Anda sehingga satu proses membuka pipa untuk dibaca sebelum proses lainnya mulai menulis. Jika proses pembacaan tidak pernah dimulai, atau berhenti tiba-tiba, menulis ke pipa atau FIFO memunculkan sinyal SIGPIPE. Jika SIGPIPE diblokir, ditangani atau diabaikan, panggilan yang melanggar gagal dengan EPIPE sebagai gantinya.
File khusus Pipa dan FIFO dibahas lebih rinci dalam Pipa dan FIFO.
sumber
Saya pikir ini adalah untuk mendapatkan penanganan kesalahan yang benar tanpa memerlukan banyak kode dalam segala hal yang menulis ke pipa.
Beberapa program mengabaikan nilai kembalian
write()
; tanpaSIGPIPE
mereka akan menghasilkan semua keluaran.Program yang memeriksa nilai pengembalian
write()
kemungkinan akan mencetak pesan kesalahan jika gagal; hal ini tidak sesuai untuk pipa yang rusak karena sebenarnya ini bukan kesalahan untuk seluruh pipa.sumber
Info mesin:
Linux 3.2.0-53-generik # 81-Ubuntu SMP Kam 22 Agustus 21:01:03 UTC 2013 x86_64 x86_64 x86_64 GNU / Linux
gcc versi 4.6.3 (Ubuntu / Linaro 4.6.3-1ubuntu5)
Saya menulis kode ini di bawah ini:
Keluaran:
Anda dapat melihat bahwa dalam setiap contoh
SIGPIPE
hanya diterima setelah lebih dari 3 karakter (dicoba) ditulis oleh proses penulisan.Apakah ini tidak membuktikan bahwa
SIGPIPE
tidak dihasilkan segera setelah proses pembacaan berakhir tetapi setelah upaya untuk menulis lebih banyak data ke pipa tertutup?sumber