Menurut halaman manual open(2), Anda dapat meneruskan O_RDONLY|O_NONBLOCK
atau O_WRONLY|O_NONBLOCK
untuk menghindari open
syscall untuk diblokir (Anda akan mendapatkan errno == ENXIO
dalam hal ini)
Saat saya berkomentar, baca juga halaman manual fifo(7) dan mkfifo(3).
Pertama, beberapa pendahuluan:
Menggunakan O_NONBLOCK
dan poll()
adalah praktik umum - bukan sebaliknya. Agar berhasil bekerja, Anda harus memastikan untuk menangani semua poll()
dan read()
mengembalikan status dengan benar:
read()
mengembalikan nilai0
berarti EOF - pihak lain telah menutup koneksinya. Ini sesuai (biasanya, tetapi tidak pada semua OS) kepoll()
mengembalikanPOLLHUP
revent. Anda mungkin ingin memeriksaPOLLHUP
sebelum mencobaread()
, tetapi tidak mutlak diperlukan sejakread()
dijamin akan mengembalikan0
setelah sisi tulisan ditutup.- Jika Anda memanggil
read()
sebelum seorang penulis terhubung, dan Anda memilikiO_RDONLY | O_NONBLOCK
, Anda akan mendapatkan EOF (read()
mengembalikan0
) berulang kali, seperti yang Anda perhatikan. Namun, jika Anda menggunakanpoll()
untuk menungguPOLLIN
acara sebelum memanggilread()
, itu akan menunggu penulis terhubung, dan tidak menghasilkan EOF. read()
mengembalikan nilai-1
biasanya berarti kesalahan. Namun, jikaerrno == EAGAIN
, ini berarti tidak ada lagi data yang tersedia saat ini dan Anda tidak memblokir, jadi Anda dapat kembali kepoll()
jika perangkat lain perlu ditangani. Jikaerrno == EINTR
, laluread()
terputus sebelum membaca data apa pun, dan Anda dapat kembali kepoll()
atau cukup panggilread()
lagi segera.
Sekarang, untuk Linux:
- Jika Anda membuka di sisi baca dengan
O_RDONLY
, lalu:open()
akan memblokir sampai ada penulis yang sesuai terbuka.poll()
akan memberikanPOLLIN
revent saat data siap dibaca, atau EOF terjadi.read()
akan memblokir sampai jumlah byte yang diminta dibaca, koneksi ditutup (mengembalikan 0), itu terganggu oleh sinyal, atau terjadi kesalahan IO yang fatal. Jenis pemblokiran ini mengalahkan tujuan penggunaanpoll()
, itulah sebabnyapoll()
hampir selalu digunakan denganO_NONBLOCK
. Anda dapat menggunakanalarm()
untuk bangun dariread()
setelah waktu tunggu, tapi itu terlalu rumit.- Jika penulis menutup, maka pembaca akan menerima
poll()
POLLHUP
revent danread()
akan mengembalikan0
sesudahnya tanpa batas waktu. Pada titik ini, pembaca harus menutup pegangan file dan membukanya kembali.
- Jika Anda membuka di sisi baca dengan
O_RDONLY | O_NONBLOCK
, lalu:-
open()
tidak akan memblokir. poll()
akan memberikanPOLLIN
revent ketika data siap dibaca, atau EOF terjadi.poll()
juga akan memblokir sampai penulis tersedia, jika tidak ada.- Setelah semua data yang tersedia saat ini dibaca,
read()
akan mengembalikan -1 dan menyetelerrno == EAGAIN
jika koneksi masih terbuka, atau akan mengembalikan0
jika koneksi ditutup (EOF) atau belum dibuka oleh penulis . Ketikaerrno == EAGAIN
, ini berarti saatnya untuk kembali kepoll()
, karena koneksi terbuka tetapi tidak ada data lagi. Ketikaerrno == EINTR
,read()
belum membaca byte dan terganggu oleh sinyal, sehingga dapat dimulai ulang. - Jika penulis menutup, maka pembaca akan menerima
poll()
POLLHUP
revent, danread()
akan mengembalikan0
sesudahnya tanpa batas waktu. Pada titik ini pembaca harus menutup pegangan file dan membukanya kembali.
-
- (khusus Linux:) Jika Anda membuka di sisi baca dengan
O_RDWR
, lalu:open()
tidak akan memblokir.poll()
akan memberikanPOLLIN
revent ketika data siap untuk dibaca. Namun, untuk pipa bernama, EOF tidak akan menyebabkanPOLLIN
atauPOLLHUP
revents.read()
akan memblokir sampai jumlah byte yang diminta dibaca, itu terganggu oleh sinyal, atau terjadi kesalahan IO fatal lainnya. Untuk pipa bernama, itu tidak akan mengembalikanerrno == EAGAIN
, bahkan tidak akan mengembalikan0
satu dari. Itu hanya akan duduk di sana sampai jumlah persis byte yang diminta dibaca, atau sampai menerima sinyal (dalam hal ini akan mengembalikan jumlah byte yang telah dibaca sejauh ini, atau mengembalikan -1 dan menyetelerrno == EINTR
jika tidak ada byte yang dibaca sejauh ini).- Jika penulis menutup, pembaca tidak akan kehilangan kemampuan untuk membaca pipa bernama nanti jika penulis lain membuka pipa bernama, tetapi pembaca juga tidak akan menerima pemberitahuan apa pun.
- (khusus Linux:) Jika Anda membuka sisi baca dengan
O_RDWR | O_NONBLOCK
, lalu:open()
tidak akan memblokir.poll()
akan memberikanPOLLIN
revent ketika data siap untuk dibaca. Namun, EOF tidak akan menyebabkanPOLLIN
atauPOLLHUP
revent pada pipa bernama.- Setelah semua data yang tersedia saat ini dibaca,
read()
akan mengembalikan-1
dan aturerrno == EAGAIN
. Inilah saatnya untuk kembali kepoll()
untuk menunggu lebih banyak data, kemungkinan dari aliran lain. - Jika penulis menutup, pembaca tidak akan kehilangan kemampuan untuk membaca pipa bernama nanti jika penulis lain membuka pipa bernama. Koneksi tetap ada.
Seperti yang Anda khawatirkan, gunakan O_RDWR
dengan pipa tidak standar, POSIX atau di tempat lain.
Namun, karena pertanyaan ini tampaknya sering muncul, cara terbaik di Linux untuk membuat "pipa bernama tangguh" yang tetap hidup meskipun satu sisi ditutup, dan yang tidak menyebabkan POLLHUP
kembalikan atau kembalikan 0
untuk read()
, adalah menggunakan O_RDWR | O_NONBLOCK
.
Saya melihat tiga cara utama menangani pipa bernama di Linux:
-
(Portabel.) Tanpa
poll()
, dan dengan satu pipa:open(pipe, O_RDONLY);
- Lingkaran utama:
read()
data sebanyak yang diperlukan, mungkin berulang padaread()
panggilan.- Jika
read() == -1
danerrno == EINTR
,read()
lagi. - Jika
read() == 0
, sambungan ditutup, dan semua data telah diterima.
- Jika
-
(Portabel.) Dengan
poll()
, dan dengan harapan bahwa pipa, bahkan yang bernama, hanya dibuka sekali, dan setelah ditutup, harus dibuka kembali oleh pembaca dan penulis, menyiapkan pipa baru:open(pipe, O_RDONLY | O_NONBLOCK);
- Lingkaran utama:
poll()
untukPOLLIN
peristiwa, mungkin pada beberapa pipa sekaligus. (Catatan:Ini mencegahread()
dari mendapatkan beberapa EOF sebelum seorang penulis terhubung.)read()
data sebanyak yang diperlukan, kemungkinan pengulangan padaread()
panggilan.- Jika
read() == -1
danerrno == EAGAIN
, kembali kepoll()
langkah. - Jika
read() == -1
danerrno == EINTR
,read()
lagi. - Jika
read() == 0
, koneksi ditutup, dan Anda harus mengakhiri, atau menutup dan membuka kembali pipa.
- Jika
-
(Non-portabel, khusus Linux.) Dengan
poll()
, dan dengan harapan bahwa pipa bernama tidak pernah berakhir, dan dapat terhubung dan terputus berkali-kali:open(pipe, O_RDWR | O_NONBLOCK);
- Lingkaran utama:
poll()
untukPOLLIN
acara, mungkin di beberapa pipa sekaligus.read()
data sebanyak yang diperlukan, mungkin berulang padaread()
panggilan.- Jika
read() == -1
danerrno == EAGAIN
, kembali kepoll()
langkah. - Jika
read() == -1
danerrno == EINTR
,read()
lagi. - Jika
read() == 0
, ada yang salah -- seharusnya tidak terjadi denganO_RDWR
pada pipa bernama, tetapi hanya denganO_RDONLY
atau pipa tanpa nama; itu menunjukkan pipa tertutup yang harus ditutup dan dibuka kembali. Jika Anda mencampur pipa bernama dan tidak bernama dalampoll()
yang sama loop penanganan peristiwa, kasus ini mungkin masih perlu ditangani.
- Jika