open(2) man ページによると、 O_RDONLY|O_NONBLOCK
を渡すことができます または O_WRONLY|O_NONBLOCK
open
を避けるために ブロックされる syscall (errno == ENXIO
が返されます) その場合)
私がコメントしたように、fifo(7) と mkfifo(3) の man ページも読んでください。
まず、準備事項:
O_NONBLOCK
の使用 および poll()
が一般的であり、その逆ではありません。正常に動作するには、すべての poll()
を確実に処理する必要があります と read()
状態を正しく返す:
read()
0
の戻り値 は EOF を意味します -- 反対側が接続を閉じました。これは (通常、すべての OS ではありませんが)poll()
に対応します。POLLHUP
を返す 反省する。POLLHUP
を確認することをお勧めします。read()
を試みる前に 、しかしread()
以来、絶対に必要というわけではありません0
を返すことが保証されています 書き込み側が閉じた後。read()
を呼び出した場合 ライターが接続する前で、O_RDONLY | O_NONBLOCK
があります 、EOF(read()
)を取得します0
を返す )お気づきのとおり、繰り返し。ただし、poll()
を使用するとPOLLIN
を待つread()
を呼び出す前のイベント 、ライターが接続するのを待ち、EOF を生成しません。read()
戻り値-1
通常はエラーを意味します。ただし、errno == EAGAIN
の場合 、これは単に現在利用可能なデータがなく、ブロックしていないことを意味するため、poll()
に戻ることができます 他のデバイスの取り扱いが必要な場合。errno == EINTR
の場合 、次にread()
データを読み取る前に中断されたため、poll()
に戻ることができます または単にread()
を呼び出します すぐにもう一度。
さて、Linux の場合:
- 読み込み側で
O_RDONLY
で開く場合 、次に:open()
対応するライターが開かれるまでブロックします。poll()
POLLIN
を返します データの読み取り準備が整ったとき、または EOF が発生したときの再試行read()
要求されたバイト数が読み取られるか、接続が閉じられる (0 が返される) か、シグナルによって中断されるか、致命的な IO エラーが発生するまでブロックされます。このようなブロッキングは、poll()
を使用する目的を無効にします。 、これがpoll()
の理由です ほとんどの場合O_NONBLOCK
で使用されます .alarm()
を使用できますread()
から目覚める タイムアウト後ですが、それは複雑すぎます。- ライターが閉じると、リーダーは
poll()
を受け取りますPOLLHUP
revent とread()
0
を返します 以降無期限。この時点で、リーダーはファイルハンドルを閉じてから再度開く必要があります。
- 読み込み側で
O_RDONLY | O_NONBLOCK
で開いた場合 、次に:open()
ブロックしません。poll()
POLLIN
を返します データを読み取る準備ができたとき、または EOF が発生したときは、revent します。poll()
ライターが存在しない場合は、ライターが使用可能になるまでブロックします。- 現在利用可能なすべてのデータが読み取られた後、
read()
-1 を返し、errno == EAGAIN
を設定します。 接続がまだ開いている場合、または0
が返されます 接続が閉じている (EOF) またはライターによってまだ開かれていない場合 .errno == EAGAIN
の場合 、これはpoll()
に戻る時が来たことを意味します 、接続は開いていますが、それ以上データがないためです。errno == EINTR
の場合 、read()
まだバイトを読み取っておらず、シグナルによって中断されたため、再起動できます。 - ライターが閉じると、リーダーは
poll()
を受け取りますPOLLHUP
反省し、read()
0
を返します 以降無期限。この時点で、リーダーはファイルハンドルを閉じてから再度開く必要があります。
- (Linux 固有:)
O_RDWR
で読み取り側で開いた場合 、次に:open()
ブロックしません。poll()
POLLIN
を返します データを読み取る準備ができたら、revent します。ただし、名前付きパイプの場合、EOF はPOLLIN
を引き起こしません。 またはPOLLHUP
read()
要求されたバイト数が読み取られるか、シグナルによって中断されるか、その他の致命的な IO エラーが発生するまでブロックされます。名前付きパイプの場合、errno == EAGAIN
は返されません 、また0
を返すことさえありません の一つ。要求された正確なバイト数が読み取られるまで、またはシグナルを受信するまで、そのまま待機します (この場合、これまでに読み取られたバイト数を返すか、-1 を返してerrno == EINTR
を設定します)。 これまでにバイトが読み取られなかった場合)。- ライターが閉じた場合、後で別のライターが名前付きパイプを開いても、リーダーは名前付きパイプを読み取ることができなくなりますが、リーダーは通知を受け取りません。
- (Linux 固有:)
O_RDWR | O_NONBLOCK
で読み取り側で開いた場合 、次に:open()
ブロックしません。poll()
POLLIN
を返します データを読み取る準備ができたら、revent します。ただし、EOF はPOLLIN
を引き起こしません。 またはPOLLHUP
名前付きパイプのrevents.- 現在利用可能なすべてのデータが読み取られた後、
read()
-1
を返しますerrno == EAGAIN
を設定します .今こそpoll()
に戻る時です おそらく他のストリームから、さらにデータを待ちます。 - ライターが閉じても、後で別のライターが名前付きパイプを開いても、リーダーは名前付きパイプを読み取ることができなくなります。接続は永続的です。
ご指摘のとおり、 O_RDWR
を使用して with pipes は POSIX などの標準ではありません。
ただし、この質問は頻繁に出てくるようなので、Linux で、片側が閉じても生き続け、POLLHUP
を引き起こさない「回復力のある名前付きパイプ」を作成する最善の方法は、 反論または 0
を返します read()
の場合 、 O_RDWR | O_NONBLOCK
を使用することです .
Linux で名前付きパイプを処理する主な方法は 3 つあります。
<オール>
(ポータブル。) poll()
なし 、および単一のパイプを使用:
open(pipe, O_RDONLY);
- メインループ:
read()
read()
でループする可能性がある、必要なだけのデータ 呼び出します。- If
read() == -1
とerrno == EINTR
、read()
もう一度。 - If
read() == 0
、接続が閉じられ、すべてのデータが受信されました。
- If
(ポータブル。) poll()
で 、そして、名前付きパイプであっても、パイプは一度しか開かれず、一度閉じられると、新しいパイプラインを設定して、リーダーとライターの両方によって再度開かれる必要があることを期待して:
open(pipe, O_RDONLY | O_NONBLOCK);
- メインループ:
poll()
POLLIN
の場合 イベント、おそらく一度に複数のパイプで。 (注:これにより、read()
が防止されます ライターが接続する前に複数の EOF を取得しないようにします)read()
必要なだけのデータ、おそらくread()
でループ 呼び出します。- If
read() == -1
そしてerrno == EAGAIN
、poll()
に戻ります ステップ。 - If
read() == -1
およびerrno == EINTR
、read()
もう一度。 - If
read() == 0
、接続が閉じられているため、パイプを終了するか、閉じてから再度開く必要があります。
- If
(非移植性、Linux 固有。) poll()
を使用 、および名前付きパイプが終了することはなく、複数回接続および切断される可能性があることを期待して:
open(pipe, O_RDWR | O_NONBLOCK);
- メインループ:
poll()
POLLIN
の場合 イベント、おそらく一度に複数のパイプで。read()
必要なだけのデータ、おそらくread()
でループ 呼び出します。- If
read() == -1
とerrno == EAGAIN
、poll()
に戻ります ステップ。 - If
read() == -1
とerrno == EINTR
、read()
もう一度。 - If
read() == 0
、何かが間違っています --O_RDWR
では発生しないはずです 名前付きパイプで、ただしO_RDONLY
のみ または名前のないパイプ。閉じて再度開く必要がある閉じたパイプを示します。名前付きパイプと名前なしパイプを同じpoll()
に混在させた場合 イベント処理ループ、このケースはまだ処理する必要があるかもしれません.
- If