基本的に、私は 2 つのプロセスが同時に同じファイルを開くとどうなるかを理解しようとしています。また、これを使用してプロセス間の通信を安全かつ効率的に提供できるかどうかを理解しようとしています。
read
を使用して通常のファイルを使用している場合 と write
操作 (つまり、それらをメモリ マッピングしない) の場合、2 つのプロセスはメモリを共有しません。
- Java
Buffer
のユーザー空間メモリ ファイルに関連付けられたオブジェクトは、アドレス空間間で共有されません。 write
のとき システムコールが行われ、データがコピーされます 1 つのプロセス アドレス空間のページからカーネル空間のページへ。 (これらはできます ページキャッシュ内のページになります。これは OS 固有です。)read
の場合 システムコールが行われ、データがコピーされます カーネル空間のページから読み取りプロセスのアドレス空間のページまで。
そのようにしなければなりません。オペレーティング システムがリーダーとライターに関連付けられたページを共有し、背後でバッファーを処理する場合、それはセキュリティ/情報漏えいの穴になります:
- リーダーは、
write(...)
を介してまだ書き込まれていないライターのアドレス空間のデータを見ることができます。 、おそらく決してそうではないでしょう。 - ライターは、リーダーが (仮説的に) 読み取りバッファーに書き込んだデータを見ることができます。
- メモリ保護の粒度は
read(...)
の粒度ではなくページであるため、メモリ保護を巧みに使用しても問題に対処することはできません。 とwrite(...)
これはわずか 1 バイトです。
確かに、ファイルの読み取りと書き込みを安全に使用して、2 つのプロセス間でデータを転送できます。ただし、ライターが書き込んだデータの量をリーダーが認識できるようにするプロトコルを定義する必要があります。そして、読者はいつを知っていますか 作家は、ポーリングを伴う可能性のある何かを書いています。例えばファイルが変更されているかどうかを確認します。
これを通信「チャネル」でのデータのコピーだけで見ると
-
メモリ マップト ファイルを使用して、データをアプリケーション ヒープ オブジェクトからマップされたバッファーにコピー (シリアル化) し、マップされたバッファーからアプリケーション ヒープ オブジェクトにもう一度 (逆シリアル化) します。
-
通常のファイルには、2 つの追加のコピーがあります。1) 書き込みプロセス (マップされていない) バッファーからカーネル空間ページ (ページ キャッシュなど) へ、2) カーネル空間ページから読み取りプロセス (マップされていない) バッファーへ。 .
以下の記事では、従来の読み取り/書き込みとメモリ マッピングで何が行われているのかを説明しています。 (これはファイルのコピーと「ゼロコピー」のコンテキストにありますが、無視してかまいません。)
参照:
- ゼロコピー I:ユーザーモードの視点