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()を受け取りますPOLLHUPrevent と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を引き起こしません。 またはPOLLHUPread()要求されたバイト数が読み取られるか、シグナルによって中断されるか、その他の致命的な 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