threadprocs とは?プロセスなのにポインタを共有できる新発想のLinuxアーキテクチャを解説

元記事を読む
キュレーターコメント

「プロセスなのにポインタが共有できる」という一文だけで興奮できるシステムプログラマーに刺さる一作。OSの仕組みを底から理解したいエンジニアにとって、実装を読むだけで学びが多い実験プロジェクトです。

概要

「プロセス間でポインタをゼロコピーで渡せたら」と思ったことはないだろうか。threadprocs(スレッドプロセス)はまさにその夢を実現しようとする実験的プロジェクトだ。複数の独立した実行ファイルを単一の仮想アドレス空間に展開しながら、それぞれが別プロセスとして振る舞うという、これまでのUNIXの常識を揺さぶるアプローチである。

背景:スレッドとプロセスの「いいとこ取り」問題

従来のLinuxプログラミングにおいて、並行処理の設計には大きなトレードオフが存在した。

  • スレッド(pthread等): アドレス空間を共有するのでポインタ渡しが自由だが、クラッシュが全体に波及し、グローバル変数も共有される
  • プロセス(fork/exec): 独立性が高く安全だが、データのやり取りにはIPC(パイプ・共有メモリ・ソケット)が必要でコピーコストが発生する
  • dlopen プラグイン: 同一アドレス空間でライブラリを動的ロードできるが、main() 関数を持つ「普通の実行ファイル」は扱えない

threadprocs はこのどれとも異なる第四の選択肢を提示している。

技術的仕組み:どうやって「プロセスなのにポインタ共有」を実現するか

threadprocs の核心は、複数の実行ファイルを同一の仮想アドレス空間にマッピングすることにある。通常、execve() を呼ぶと新プロセスは独自のアドレス空間を持つ。threadprocs はこれを回避し、親プロセスのアドレス空間に複数の main() 付き実行バイナリをロードする。

[プロセスA] ─┐
             ├─ 共有仮想アドレス空間 (一つのmmap領域)
[プロセスB] ─┘

   ポインタがそのまま有効(コピー不要)

各 threadproc は以下の点で独立を保つ:

  • 独自のグローバル変数領域(コピーオンライト的に分離)
  • 独自のライフタイム(一方がクラッシュしても他方への影響を最小化)
  • 独自の main() エントリポイント(dlopen とは違い、普通のバイナリをそのまま実行)

そして共有するのは仮想アドレス空間のレイアウトだけだ。これにより、あるthreadprocが持つポインタをそのまま別のthreadprocに渡しても、アドレスが一致するためデリファレンスが可能になる。コード変更は原則不要で、「well-behaved な Linux バイナリ」であればそのまま動作するとされている。

ユースケース:どんな場面で使えるか

まだ実験段階だが、このアーキテクチャが実用化されれば以下のシナリオが考えられる:

  • マイクロサービスのゼロコピー連携: 大量データを扱うサービス間でシリアライズなしにポインタを渡せる
  • プラグインシステムの安全な実装: クラッシュ隔離を保ちながら通常の実行ファイルをプラグインとして扱う
  • レガシーバイナリの組み合わせ実行: ソースなしの既存バイナリを組み合わせてパイプライン構築
  • ゲームエンジンのモジュール分離: ゲームロジックをプロセスごとに分けつつ、ゲームオブジェクトのポインタを共有

実際に試すには、Linux 環境(カーネル 5.x 以降推奨)と Rust のツールチェーンが必要だ。リポジトリは github.com/jer-irl/threadprocs で公開されており、cargo build でビルドできる構成になっている。

まとめ・所感

threadprocs は「スレッドの利便性」と「プロセスの独立性」を同時に得ようとする野心的な実験だ。現状は experimental(実験的) との位置づけで、本番利用には程遠いが、発想そのものは非常に刺激的である。

Linuxのアドレス空間管理・mmap・ELFローダーの深い理解なしには実現できないプロジェクトであり、OSの仕組みを学ぶ教材としても優秀だ。特にシステムプログラミングに興味があるエンジニアや、IPC のオーバーヘッドに悩んでいるアーキテクトには、一読の価値がある。ゼロコピーIPC の未来形として注目しておきたいプロジェクトだ。