IPCの設計比較(パイプ・SysV・POSIX・mq)
同じ「プロセス間通信」でも、帯域・レイテンシ・名前空間・永続性はまるで違います。パイプからSysV/POSIX共有メモリ、Unixドメインソケットまで、選定の軸を系統で整理し迷わず選べるようになります。
- 1.IPCは「データを流す系(パイプ/FIFO/ソケット)」と「メモリを共有する系(共有メモリ+同期)」に大別でき、前者はコピーを伴い帯域が律速、後者はゼロコピーだが排他制御が利用者責任になる。
- 2.名前空間と永続性が設計の分かれ目。SysV IPCはkey/ID(カーネル寿命)、POSIX IPCは名前(/name、ファイル的寿命)、パイプはfd継承、FIFO/Unixソケットはファイルシステムのパスで名付ける。
- 3.最速はゼロコピーの共有メモリだが同期を別途要し、双方向+多重化+fd受け渡しの実用性ではUnixドメインソケットが定番。POSIXメッセージキューは優先度付き・非同期通知に強い。
比較の軸を先に決める
IPCは プロセス間通信(IPC) の総称ですが、上級者が実装方式を選ぶときに本当に効く軸は4つに絞れます。これを最初に固定しておくと、雑多に見える各方式が一枚の地図に収まります。
- 帯域(throughput): 大量データを流したときのコピー回数が支配的。
read/writeを介す方式は最低でもユーザー→カーネル→ユーザーの2コピーが入り、共有メモリはコピー0回。 - レイテンシ(latency): 1回のやり取りに要するシステムコール回数とモード遷移。共有メモリ+busy-wait なら syscall ゼロも可能、ソケットは送受それぞれで遷移が入る。
- 名前空間(namespace): 無関係なプロセスがどうやって同じ通信路に出会うか。fd継承・ファイルパス・key/ID・
/name文字列のどれを使うかで「誰と話せるか」が決まる。 - 永続性(persistence): 全プロセスが終了した後も通信路が残るか。これは「明示的に削除しないとリークする」という運用上の落とし穴に直結する。
系統の分岐:データストリーム系とメモリ共有系
まず大きな分岐を押さえます。IPCは「バイト/メッセージを転送する系」と「メモリ領域そのものを共有する系」に分かれ、この違いがコピーの有無を決めます。
IPC機構
├─ データ転送系(カーネルがバッファを仲介、コピーあり)
│ ├─ パイプ(匿名) … fd継承で名付け、バイトストリーム
│ ├─ FIFO(名前付きパイプ)… ファイルパスで名付け、バイトストリーム
│ ├─ SysVメッセージキュー … key/ID、type付きメッセージ
│ ├─ POSIXメッセージキュー … /name、優先度付きメッセージ+非同期通知
│ └─ Unixドメインソケット … パス or 抽象名、双方向+fd受け渡し
└─ メモリ共有系(同じ物理ページを写像、コピーなし)
├─ SysV共有メモリ … key/ID(shmget/shmat)
├─ POSIX共有メモリ … /name(shm_open+mmap)
└─ mmap無名共有 … fork経由、MAP_SHARED|MAP_ANONYMOUS
データ転送系は カーネル内バッファが順序と排他を保証 してくれるため、利用者は同期を考えずに済みます。代わりに送受でコピーが入り、帯域はメモリ帯域とコピー回数で頭打ちになります。メモリ共有系は コピーが0回でゼロコピー ですが、「いつ誰が書いていいか」の保証がカーネルから一切提供されません。順序・排他は利用者が セマフォ などで自前で設計する必要があります。これが「共有メモリは最速だが最も危険」と言われる構造的な理由です。
パイプとFIFO:最も素朴なバイトストリーム
パイプは pipe() が返す読み/書き2本のfdで、fd継承(fork)でしか相手に渡せない ため親子・兄弟プロセス間に限られます。一方向・バイトストリーム・順序保証ありで、シェルの ls | grep がまさにこれです。
FIFO(名前付きパイプ)は mkfifo でファイルシステム上にパスを持つ特殊ファイルを作り、無関係なプロセスが同じパスを open することで出会えます。中身の挙動はパイプと同じバイトストリームですが、名前空間がfd継承からファイルパスへ広がる点が本質的な違いです。
Linuxのパイプ/FIFOはカーネル内に固定容量のリングバッファ(既定64KiB)を持ちます。PIPE_BUF(Linuxでは4096バイト)以下の write はアトミックで、複数writerが混ざっても1回の書き込みが分断されません。これを超えるサイズは途中で他writerのデータが割り込みうるため、複数writerでメッセージ境界を保ちたいなら PIPE_BUF 以下に収めるか、メッセージ指向のIPCを選びます。
SysV対POSIX:同じ機能の二系統をどう見分けるか
共有メモリ・セマフォ・メッセージキューには、それぞれ System V(SysV)系 と POSIX系 の2つのAPIが存在します。機能は重なりますが、名前空間と寿命の設計思想が違います。
| 観点 | System V IPC | POSIX IPC |
|---|---|---|
| 名付け | key_t(ftokやIPC_PRIVATEで生成)→ get系がIDを返す | /name 文字列(先頭スラッシュ+名前) |
| ハンドル | 整数のIPC ID(fdではない) | fd(共有メモリ/mqはfdとして扱える) |
| 寿命 | カーネル寿命:明示削除まで残る(プロセス終了で消えない) | ファイル的寿命:参照0かつ明示unlinkで消える |
| 列挙・管理 | ipcs / ipcrm で一覧・削除できる | /dev/shm や /dev/mqueue 上のファイルとして見える |
| API例 | shmget/shmat, semget/semop, msgget/msgsnd | shm_open+mmap, sem_open, mq_open/mq_send |
| 設計の古さ | 古典的・移植性高いが整数IDで扱いにくい | 新しめ・fd統合でselect/epollと相性が良い |
実務上の含意は明快です。SysVはカーネル寿命なので、作ったIPCオブジェクトを明示的に ipcrm / shmctl(IPC_RMID) しないと、全プロセスが死んでも残り続けてリークします。ipcs で残骸が積み上がるトラブルはこれが原因です。POSIX系はfdとして扱え、shm_open した共有メモリは /dev/shm/ 配下のファイルとして現れ、epoll で待てるmqと合わせて、近代的なイベント駆動と統合しやすい設計です。
SysV IPCの寿命はカーネルにひも付きます。デバッグ中にプロセスをkillしても、確保した共有メモリセグメントやセマフォは残り、ipcs -m に居座ります。再実行のたびに ftok が同じkeyを返すと既存セグメントに当たり、サイズ不一致や古いデータで誤動作します。後始末は ipcrm か、コード側で IPC_RMID を必ず通す運用が要ります。
共有メモリ:ゼロコピーの代償は同期
共有メモリ系は、複数プロセスが同じ物理ページを各自のアドレス空間に写像する仕組みで、本質的には メモリマップトファイル(mmap) と同じページテーブル操作です。POSIXなら shm_open でfdを得て mmap(..., MAP_SHARED, ...)、SysVなら shmget+shmat。一度写像すれば、以後の読み書きは ただのメモリアクセスでありシステムコールを伴いません。これが帯域・レイテンシで他を圧倒する理由です。
代償は、順序保証も排他保証もカーネルから提供されない ことです。生産者・消費者を安全に回すには、別途同期プリミティブが要ります。
共有メモリでリングバッファを安全に回す骨格:
共有領域 = ヘッダ{ head, tail } + データ配列
producer:
sem_wait(empty_slots) # 空きスロットを1つ確保(なければ眠る)
buf[tail] = item # ゼロコピーで直接書き込み
tail = (tail + 1) % N
sem_post(filled_slots) # 「1件入った」を通知
consumer:
sem_wait(filled_slots) # 中身を1つ確保
item = buf[head]
head = (head + 1) % N
sem_post(empty_slots) # 「1枠空いた」を通知
ここで head/tail の更新順とメモリ可視性が崩れるとデータ破壊が起きます。マルチコアではセマフォだけでなくメモリバリアの考慮も必要で、設計の難度は他方式より明確に高くなります。共有メモリは「速さと引き換えに正しさの責任を利用者が背負う」方式だと理解しておくのが要点です。
メッセージキュー:境界と優先度を持つ非同期
メッセージキューは、バイトストリームではなくメッセージ単位 で送受信する点がパイプと根本的に違います。受信側は1メッセージを丸ごと受け取り、境界が自然に保たれます。
- SysVメッセージキュー: 各メッセージに
long mtype(メッセージ型)を持たせ、受信時に型を指定して 任意の型だけ選んで取り出せる。1つのキューを多重化した簡易ルーティングに使えます。 - POSIXメッセージキュー: メッセージに 優先度 を付与でき、受信は常に最高優先度・最古のものから。さらに
mq_notifyで キューが空から非空に変わった瞬間に非同期通知(シグナルやスレッド起動)を受けられ、ポーリング不要のイベント駆動が組めます。fdとして扱えるためLinuxではepollでも待てます。
メッセージキューは「タイミングがずれても溜めてくれる非同期バッファ」であり、構造化された制御メッセージのやり取りに向きます。一方で1メッセージごとにコピーが入るため、大量データのバルク転送には共有メモリのほうが適します。
Unixドメインソケット:実務の万能選手
同一ホスト内通信で最も汎用なのが Unixドメインソケット です。APIはネットワークソケットと同一(socket/bind/connect/send/recv)で、TCPのような順序保証ストリーム(SOCK_STREAM)も、メッセージ境界を保つ SOCK_DGRAM / SOCK_SEQPACKET も選べます。
決定的な強みは2つあります。第一に 双方向で、epoll による多重化と素直に統合 できること。第二に、補助データ(SCM_RIGHTS)でファイルディスクリプタそのものを別プロセスへ受け渡せる ことです。これは他のIPCにない能力で、特権プロセスが開いたソケットやファイルを非特権ワーカーへ渡す権限分離パターン(多くのサーバーやコンテナランタイムが使う)の基盤になっています。名前空間はファイルパス(/run/foo.sock)か、Linux固有の 抽象名前空間(先頭がヌルバイトでファイルシステムに痕跡を残さない)を選べます。
ベンチマーク上はパイプや共有メモリのほうがレイテンシが低い場面が多くあります。それでもUnixドメインソケットが定番なのは、双方向・メッセージ境界・多重化・fd受け渡し・接続という抽象を1つのAPIで一貫して提供し、後からネットワーク(TCP)へ載せ替えるのも容易だからです。「まずUnixソケット、帯域が問題になったら共有メモリ」が堅実な順序です。
総合比較表
| 方式 | 帯域 | レイテンシ | 名前空間 | 永続性 | 向く用途 |
|---|---|---|---|---|---|
| パイプ(匿名) | 中(2コピー) | 低 | fd継承(親子のみ) | なし(最後のfdで消滅) | 親子のストリーム連結 |
| FIFO | 中(2コピー) | 低 | ファイルパス | パス自体は残る/中身は揮発 | 無関係プロセスのストリーム |
| SysV共有メモリ | 最高(0コピー) | 最低(同期次第) | key/ID | カーネル寿命(明示削除要) | 大量データ・低遅延 |
| POSIX共有メモリ | 最高(0コピー) | 最低(同期次第) | /name(fd) | ファイル的(unlinkで消滅) | 近代的な大量データ共有 |
| SysVメッセージキュー | 中 | 中 | key/ID | カーネル寿命 | 型別ルーティング |
| POSIXメッセージキュー | 中 | 中 | /name(fd) | ファイル的 | 優先度付き・非同期通知 |
| Unixドメインソケット | 中〜高 | 低〜中 | パス/抽象名 | なし(接続単位) | 双方向・多重化・fd受け渡し |
まとめ
IPCはまず データ転送系(パイプ/FIFO/メッセージキュー/ソケット、カーネルが仲介しコピーあり) と メモリ共有系(共有メモリ、ゼロコピーだが同期は利用者責任) に大別できます。選定の決め手は帯域・レイテンシ・名前空間・永続性の4軸です。同機能でも SysVはkey/IDでカーネル寿命(明示削除しないとリーク)、POSIXは/name文字列でfd統合・ファイル的寿命 という二系統がある点を取り違えないことが重要です。最速はゼロコピーの共有メモリですが順序・排他を自前で組む必要があり、双方向・多重化・fd受け渡しまで含めた実用性ではUnixドメインソケットが定番、構造化された非同期メッセージにはPOSIXメッセージキューが噛み合います。「まずUnixソケット、帯域が壁になったら共有メモリ+セマフォ」を基本線にすると外しません。基礎は プロセス間通信(IPC)、合図に限る通知は シグナル も参照してください。
- IPCは 転送系(コピーあり・同期不要) と 共有メモリ系(ゼロコピー・同期は利用者責任) に大別。
- SysV IPC=key/ID、カーネル寿命(IPC_RMIDやipcrmで明示削除しないと残る)。POSIX IPC=/name、fd扱い、ファイル的寿命(unlinkで消滅、/dev/shmや/dev/mqueueに現れる)。
- 匿名パイプは fd継承で親子限定、FIFOは ファイルパス で無関係プロセスもつなげる。
PIPE_BUF(Linux 4096)以下の書き込みはアトミック。 - Unixドメインソケット だけが
SCM_RIGHTSで fd受け渡し が可能。双方向・epoll多重化と統合しやすく実務の定番。 - POSIXメッセージキュー は優先度付き+
mq_notifyの非同期通知、SysVメッセージキュー はmtypeでの型別受信が特徴。
OS Article
IPCの設計比較(パイプ・SysV・POSIX・mq)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
IPC
比較で見る軸
難易度: advanced / カテゴリ: OS / タグ数: 6
導入後に効く点
名前空間と永続性が設計の分かれ目。SysV IPCはkey/ID(カーネル寿命)、POSIX IPCは名前(/name、ファイル的寿命)、パイプはfd継承、FIFO/Unixソケットはファイルシステムのパスで名付ける。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- OS
- タグ数
- 6
判断チェックリスト
- 自社の用途が「IPC / 共有メモリ」に近いか確認する。
- 強みである「IPCは「データを流す系(パイプ/FIFO/ソケット)」と「メモリを共有する系(共有メモリ+同期)」に大別でき、前者はコピーを伴い帯域が律速、後者はゼロコピーだが排他制御が利用者責任になる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。