以下の内容はhttps://error-daizenn.hatenablog.com/entry/2026/02/23/204130より取得しました。


WindowsのERROR_BROKEN_PIPE(109 / 0x6D)とは?原因・発生条件・アプリ側の正しい対処法

 

WindowsのERROR_BROKEN_PIPE(109 / 0x6D)とは?原因・発生条件・アプリ側の正しい対処法

Windowsでパイプ通信(名前付きパイプ/匿名パイプ)を使っていると、突然 ERROR_BROKEN_PIPE (109 / 0x6D) に遭遇することがあります。ログには「The pipe has been ended.(パイプが終了した)」とだけ出て、原因がつかみにくいのが厄介です。
この記事では、ERROR_BROKEN_PIPEの意味を「どういう状態で起きるのか」という実務視点で整理し、再現しやすい典型パターン、アプリ側の安全な扱い方、調査の手順までまとめます。

ERROR_BROKEN_PIPE(109)の意味を一言でいうと

ERROR_BROKEN_PIPE は「通信路として使っていたパイプの片側が閉じられた(終端した)のに、もう片側が読み書きしようとした」ことを示すエラーです。
重要なのは、“壊れた”というより“相手が先に終了した/切断した” というニュアンスが強い点です。例えるなら、通話相手が先に電話を切ったあとに、こちらが話し続けてしまった状態です。

どんな場面で起きる?(発生条件の典型)

パイプはプロセス間通信(IPC)でよく使われます。次のような構成で頻出します。

  • 親プロセスが子プロセスを起動し、標準入出力をパイプでつなぐ

  • サービスとクライアントを名前付きパイプで接続する

  • ワーカーとフロントエンドが匿名パイプで双方向通信する

ここで、相手側プロセスが終了したり、パイプハンドルをクローズしたりすると、残った側が WriteFile / ReadFile などを呼んだ瞬間に 109 が返ります。

よくある具体例

  • 子プロセスがエラー終了し、標準入力(stdin)の読み取りをやめたのに、親が書き込みを続けた

  • クライアントが切断(CloseHandle)したのに、サーバーが返信を書き込もうとした

  • タイムアウトやキャンセル処理で接続を閉じた直後に、別スレッドが書き込みを実行してしまった(レース)

  • 通信プロトコル上の終了手順が曖昧で、片側が先に閉じてしまう設計になっている

どのAPIで返りうる?

パイプに対する読み書きや接続に関わるWindows APIで返る可能性があります。代表例は次のとおりです。

  • WriteFile:相手が読む側を閉じたあとに書き込むと発生しやすい

  • ReadFile:相手が書く側を閉じたあと、読み取りで検出されることがある

  • その他パイプ操作系:接続状態やI/O状態に依存して返る

ポイントは、**「I/Oを実行した瞬間」**に露呈することが多い点です。接続が切れていても、次の読み書きまで気づけないケースがあります。

ERROR_BROKEN_PIPEは「異常」か「通常の切断」か

ここが設計で最重要です。ERROR_BROKEN_PIPEは、状況によっては**“正常な切断”として扱うべき**ことがあります。

  • クライアントがユーザー操作で終了 → サーバー側は「切断された」として静かに終了処理へ

  • 子プロセスが処理完了で終了 → 親プロセス側は「通信完了」として後始末へ

一方で、期待していないタイミングで頻発するなら、以下の可能性が高いです。

  • 相手が例外・クラッシュ・強制終了している

  • プロトコル(メッセージ境界、終端、フラッシュ)が合っていない

  • 多スレッドでクローズとI/Oが競合している

  • バッファ枯渇やデッドロック回避のために相手が先に閉じている

「切断=バグ」と決めつけず、**“なぜそのタイミングで相手が閉じたのか”**を切り分けるのが近道です。

開発者が取るべき基本の対処(安全な型)

ERROR_BROKEN_PIPEに遭遇したときの基本方針はシンプルです。

  1. そのパイプのI/Oを継続しない(以降の読み書きは失敗する前提)

  2. 開いているハンドルを閉じる(CloseHandle等)

  3. 関連リソースを解放(バッファ、イベント、スレッド、キューなど)

  4. 上位へ“切断”として通知(再接続するか、処理を終えるか判断)

「リトライすれば直る?」の落とし穴

通信相手がすでにいない以上、同じハンドルでのリトライは基本的に無意味です。必要なのは、

  • 再接続(新しい接続を張り直す)

  • セッション再確立(認証・初期化からやり直す)

  • 処理を正常終了へ遷移(相手終了が想定内なら)
    のいずれかです。

再発防止の設計ポイント

ERROR_BROKEN_PIPEを「起きても困らない」状態にするには、次の設計が効きます。

1) 終了手順(シャットダウン・プロトコル)を決める

片側が突然Closeするのではなく、

  • 「これで最後のメッセージ」

  • 「これ以降送らない」

  • 「ACKを受けたらクローズ」
    のように、終了を合図するメッセージを設けるとレースが減ります。

2) クローズとI/Oの競合(レース)を潰す

多スレッド構成では、片方のスレッドがCloseした直後に別スレッドがWriteして109になる、が典型です。対策としては、

  • クローズ前に送信スレッド停止→完了待ち→Close

  • ハンドルの生存管理(参照カウント、状態フラグ、ロック)

  • キャンセルAPIやイベントでI/Oを中断してから終了
    など、終了処理を手順化します。

3) エラーを「切断イベント」として扱う

例外扱いでログが赤くなるだけだと運用が辛くなります。想定内の切断なら、

  • INFOレベルで「peer disconnected」

  • メトリクスとして切断回数を記録

  • 同時に相手の終了コードや直前のメッセージを残す
    といった形で、運用可能な情報に落とし込みます。

調査のコツ(ログで見るべきポイント)

原因を掘るときは、エラー109そのものよりも「直前の流れ」が重要です。

  • 109が出たI/Oは ReadWrite

  • その直前に相手へ何を送ったか(サイズ、コマンド種別)

  • 直前にClose/Disconnect/Cancel相当の処理が走っていないか

  • 相手プロセスの終了コード、クラッシュログ、イベントログ

  • 同時刻にタイムアウトや再接続処理が走っていないか

特に、「一見ランダムに見える109」は、タイミング競合が原因のことが多いです。スレッドや非同期I/Oが絡む場合は、状態遷移のログ(Connected→Closing→Closed)を明示的に入れると特定が一気に楽になります。

関連エラーとの関係を押さえる

パイプ周りでは似た意味合いのエラーが近くに出ます。これらは「通信状態の違い」を示すヒントになります。

  • ERROR_PIPE_CONNECTED:接続状態に関するイベントで出ることがある

  • ERROR_NO_DATA:相手の状態やI/O条件によっては、109の代わりに出ることがある

  • ERROR_HANDLE_EOF:終端扱いとして出ることがある

同じ“切断”でも返り方が揺れることがあるので、アプリ側は 「切断系の戻り値をまとめて扱う」 設計にしておくと堅牢です。

まとめ:ERROR_BROKEN_PIPE(109)は「相手が先に閉じた」サイン

ERROR_BROKEN_PIPEは、パイプ通信で相手側が終了・切断し、こちらが読み書きしようとして初めて検出される典型的なエラーです。対処は「その接続は終わった」とみなしてハンドルを閉じ、リソースを解放し、必要なら再接続へ進めること。
そして再発防止の要点は、終了手順の明確化と、クローズとI/Oの競合を潰す状態管理です。109を“例外”として恐れるより、切断イベントとして設計に組み込むことで、運用も実装も一段と安定します。




以上の内容はhttps://error-daizenn.hatenablog.com/entry/2026/02/23/204130より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14