6

shm_openマニュアルページから:

新しい共有メモリ オブジェクトは、最初は長さが 0 です。オブジェクトのサイズは、ftruncate(2) を使用して設定できます。[...] shm_open() 関数自体は、指定されたサイズの共有オブジェクトを作成しません。これを行うと、ファイル記述子によって参照されるオブジェクトのサイズを設定する既存の関数が複製されるためです。

これにより、アプリケーションが競合状態にさらされることはありませんか? 次の擬似コードを検討してください。

int fd = shm_open("/foo", CREATE);
if ( fd is valid ) {
  // created shm object, so set its size
  ftruncate(fd, 128);
} else {
  fd = shm_open("/foo", GET_EXISTING);
}
void* mem = mmap(fd, 128);

shm_openとのftruncate呼び出しは (一緒に) アトミックではないため、あるプロセスが ( case ) を呼び出すが、 を呼び出す前に別のプロセスが ( case ) を呼び出してサイズ 0 のオブジェクトを試み、場合によってはそれに書き込もうとする競合状態が発生shm_openするCREATE可能ftruncateshm_openがありますGET_EXISTINGmmap

この競合状態を回避するには、次の 2 つの方法が考えられます。

  1. IPCミューテックス/セマフォを使用して全体を同期させるか、または...

  2. 安全な場合 (POSIX に従って)、とケースftruncateの両方を呼び出します。CREATEGET_EXISTING

この競合状態を回避するための推奨される方法はどれですか?

4

2 に答える 2

6

あなたのアプローチ (両方から呼び出す) は機能するはずですが、とにかく共有メモリ セグメントの内容の使用ftruncateを同期する方法が必要です。メモリは最初は空 (ゼロで埋められている) であるため、有効な同期オブジェクトが含まれていないため、アトミックを使用して独自にロールする場合を除き、共有メモリへのアクセスを制御するために、とにかく同期の 2 番目の形式が必要です。

通常、固定名の共有メモリセグメントを作成または開くために複数のプロセスを競合させるのではなく、所有者プロセスにランダムな名前のセグメントを作成させ、O_EXCLランダムまたは悪意のある衝突を引き起こし、名前を正常に開き、サイズを調整し、同期オブジェクトを作成したら、それにアクセスする必要がある他のプロセスに名前を渡します。

于 2013-05-12T01:00:19.550 に答える
1

@Rとして。ここでの別の問題は、ファイルを作成しても、ミューテックスなどのコンテンツが初期化されて使用できるようになる前にウィンドウが残っていることです。

上記とは少し異なる解決策は次のとおりです。

open() を試してください。open() が成功した場合は、単純に map() を使用し、コンテンツが既に初期化されており、使用できるという必要な保証 (以下を参照) を使用します。open() が失敗した場合は、一時ファイルを作成して初期化してから、一時ファイルを目的のファイルとしてハード リンク () し、一時ファイル名を unlink() してみてください。

link() が成功した場合、初期化されたファイルを自分自身および他のプロセスで使用できるようになりました。link() が EEXIST で失敗した場合、別のプロセスが最初にそこに到達しました (rename() とは異なり、link() はターゲット名が存在する場合に失敗します)。いずれにせよ、繰り返し open() が成功し、初期化されたすぐに使用できるファイルが作成されるはずです。

この戦略では、明らかに一時ファイルの初期化に競合状態が存在しますが、初期化プロセスが冪等であり、リソースが過度に高価ではなく、プロセスがそれぞれ一意の一時ファイルを選択する場合、これは重要ではありません。複数の初期化が問題になる可能性がある場合の解決策は、初期化を 2 段階のプロセスに分割することです。第 1 段階はファイル内の単なるミューテックスであり、第 2 段階でファイルの残りの複数の初期化を防ぐために使用されます。

于 2015-05-25T00:34:26.510 に答える