プロセス間通信(IPC:Inter-Process Communication)とは、OS上で独立して動作している複数のプロセス同士がデータをやり取りするための仕組みを指します。
一般的に、プロセスはそれぞれ独立した仮想メモリ空間を持っており、他のプロセスの変数やメモリ領域を直接参照することはできません。
この「メモリ空間の分離」は安全性や安定性のために不可欠ですが、その代わりに、プロセス間で情報を共有したい場合には、OSが提供する正式な通信手段を使う必要があります。
C++自体はIPCの機能を直接持っているわけではありませんが、OSのAPIを利用することで、多様なIPC手法を実装できます。
IPCの代表的な方式と全体像
C++で利用されるIPCには、用途や特性の異なる複数の方式があります。
それぞれは「優劣」ではなく、「前提条件と目的」によって使い分けられます。
主なIPC方式は次のとおりです。
- パイプおよび名前付きパイプ(FIFO)
- 共有メモリ
- メッセージキュー
- ソケット通信(UNIXドメインソケット、TCP/UDP)
- メモリマップトファイル(mmap)
- RPCなどの高レベル通信方式
これらは、通信頻度・データ量・安全性・将来の拡張性などの観点で選択されます。
パイプと名前付きパイプ(FIFO)
パイプは、最も古くから存在するシンプルなIPC方式です。
データは「バイトストリーム」として一方向に流れます。
無名パイプ
無名パイプは、主に親プロセスと子プロセスの間で使用されます。
プロセス生成(fork)と組み合わせて使うのが一般的で、作成したプロセス間でのみ有効です。
名前付きパイプ(FIFO)
名前付きパイプは、ファイルシステム上に実体を持つパイプです。
親子関係にないプロセス同士でも利用できる点が特徴です。
注意点
パイプやFIFOは基本的に単方向通信です。
双方向通信を実現したい場合は、パイプを複数用意するか、別のIPC方式を選ぶ必要があります。
向いている用途
- 単純なデータ受け渡し
- プロセス間の直列処理
- コマンド連携のような用途
共有メモリ
共有メモリは、複数のプロセスが同じメモリ領域を明示的に共有する方式です。
データのコピーを介さずにアクセスできるため、高い性能を引き出せる可能性があります。
ただし、共有メモリは「速い代わりに難しい」方式です。
特徴
- コピーを伴わないため、大量データのやり取りに向いている
- プロセス間で直接データ構造を共有できる
注意点
共有メモリ自体には排他制御の仕組みがありません。
そのため、同時アクセスによる競合やデータ破壊を防ぐために、セマフォやミューテックスなどの同期機構を併用する必要があります。
同期設計を誤ると、性能が低下したり、バグの温床になったりするため、設計難易度は高めです。
向いている用途
- 高頻度・低レイテンシな通信
- 大容量データの共有
- リアルタイム性が強く求められる処理
メッセージキュー
メッセージキューは、データを「メッセージ単位」で送受信するIPC方式です。
送信側と受信側が直接同期する必要がなく、非同期通信が可能です。
特徴
- キューにメッセージを積む・取り出すというモデル
- 排他制御を意識せずに使いやすい
- プログラム構造を整理しやすい
制約
- メッセージサイズやキュー全体の容量に制限がある
- 大きなデータの転送には不向き
そのため、実務では「通知や制御はメッセージキュー」「実データは別の手段(共有メモリなど)」という併用構成がよく使われます。
向いている用途
- イベント通知
- ワーカープロセス制御
- ログやタスクの分配
ソケット通信
ソケットは、IPCの中でも特に汎用性が高い方式です。
同一マシン内の通信だけでなく、ネットワーク越しの通信にも対応できます。
主な種類
- UNIXドメインソケット:同一マシン内専用で、比較的高速
- TCPソケット:信頼性のある通信、分散システム向け
- UDPソケット:軽量だが信頼性や順序保証がない
特徴
- クライアント・サーバ構成が取りやすい
- 将来的に別ホストへ分離しやすい
- デバッグや運用がしやすい
性能面では共有メモリに劣る場合もありますが、設計の柔軟性と保守性の高さから、実務では非常によく選ばれます。
メモリマップトファイル(mmap)
メモリマップトファイルは、ファイルをメモリ空間にマッピングし、メモリのように扱う方式です。
複数プロセスが同じファイルをマップすることで、結果的にデータを共有できます。
特徴
- 大容量データに向いている
- ファイルとして永続化できる
- 共有メモリと似た性質を持つ
注意点
実際の挙動は、ページキャッシュやページフォルト、書き戻しタイミングなど、OSの管理に強く依存します。
アクセスパターンによって性能特性が大きく変わるため、設計時の検討が重要です。
C++でIPC方式を選ぶ際の設計観点
IPCは「速度」だけで決めるものではありません。
以下のような観点を総合的に考慮する必要があります。
- 通信頻度は高いか低いか
- データ量は小さいか大きいか
- プロセスは多対多か一対一か
- 障害発生時にどう振る舞うべきか
- 将来、別マシンに分離する可能性があるか
- デバッグや運用のしやすさを重視するか
性能を最大化するために共有メモリを選ぶよりも、まずは安全で分かりやすい方式を選び、必要に応じて最適化するという設計が、現実の開発ではよく採られます。
まとめ
- IPCはC++における低レイヤ設計力が問われる分野
- 各方式には明確なメリットとデメリットがある
- 初期設計では、ソケットやメッセージキューのような扱いやすい方式が選ばれやすい
- 本当に性能が必要になった段階で、共有メモリなどを検討するのが現実的
以上、C++のプロセス間通信についてでした。
最後までお読みいただき、ありがとうございました。
