7

1 つのスレッドがミューテックスを保持しているプロセスの場合、すぐに子forkプロセスを実行しても比較的安全ですか? exec私より前の子供に安全にできることは何execですか?

実行するスレッドがfork子プロセスを呼び出す前にミューテックスを解放するexecと、問題が発生しますか? 親プロセスが以前に所有していた子のミューテックスを取得しようとするとどうforkなりますか (まだ所有している場合と所有していない場合があります)。

答えはプラットフォームによって異なりますか? 私は主に Unix バリアント、特に Linux に関心があります。しかし、私はNTに興味があります。もちろん、NT には (私の知る限り) はありませんfork

4

2 に答える 2

8

マルチスレッド環境に関連する問題については、 pthread_atfork、特に RATIONALE セクションを参照してください。また、子と親のfork前後で何が有効であるかについてのヒントも提供します。fork

更新: RATIONALE セクションは非規範的であり、標準の他の部分と矛盾していることが判明しました。詳細については、Dave Butenhof によるこの欠陥レポートを参照してください。

直後は、マルチスレッド プログラム (つまり、ミューテックスを保持しているスレッド) のどの状態でも安全であると想定されていますexec。と の間でfork考えられることに関しては、状況は複雑です。forkexec

最も重要なことは、1 つのスレッド ( を呼び出したスレッドfork) だけが子プロセスで複製されることです。したがって、その時点で別のスレッドによって保持されているミューテックスはfork永久にロックされます。つまり、(非プロセス共有ミューテックスを想定して) 子プロセス内のそのコピーは、ロックを解除するスレッドがないため、永久にロックされます。

後でミューテックスを解放forkすることは、可能であれば安全です。つまり、最初にforking スレッドがミューテックスを所有している場合です。通常、ハンドラは次のようpthread_atforkに動作します: の前にミューテックスforkをロックし、子でロックを解除し、親でロックを解除します。

fork の前にプロセスが所有していたミューテックスを取得した時点で (子のアドレス空間内のコピーについて説明したことを思い出してください): ing スレッドによって所有されていた場合、それはfork再帰ロックです ( に対して機能しPTHREAD_MUTEX_RECURSIVEます)。別のスレッドが所有していた場合、永久にロックされたままになり、再取得できなくなります。

適切なハンドラを登録することにより、サードパーティ ライブラリは と の間でpthread_atfork安全に使用できることを保証できます。(汎用ライブラリではなく、主にプログラミング言語ランタイムから期待されます)。forkexec


さらに調査した後、 に依存することは避け、 と の間の async-signal-safe 呼び出し以外は何もしないことをお勧めしますpthread_atfork( /を放棄することはさらに良いでしょう)。forkexecforkexecposix_spawn

問題は、forkそれ自体がシグナルハンドラーで呼び出される可能性があることです。pthread_atforkその RATIONALE がミューテックスのロック解除と子プロセスでのスレッドの再作成 (!) を明示的に言及している場合でも、それは の重要な使用を排除します。

考えられるさまざまな解釈の「灰色の領域」が残っていると思います。

  1. シグナル ハンドラを呼び出さないことがわかっpthread_atforkているプログラム内のハンドラの場合。fork
  2. シグナルハンドラーにないfork呼び出しの周りで発生する非 pthread-atfork アクションの場合。

しかし、どの読み取り値がポータブル アプリケーションに使用されるかは明らかです。

于 2013-01-18T21:34:51.627 に答える
1

exec() によって置き換えられるプログラムがミューテックスを所有している場合、 fork() の後に exec() を実行しても安全です。ミューテックスがライブラリの一部であり、シリアルにアクセスする必要があるリソースを保護している場合、pthread_atfork() を呼び出してコールバックを登録する必要があります。

  1. fork 自体の前に、 fork() システム コールを行うスレッドのコンテキストで呼び出される関数。通常、この関数は、クリティカル セクションを保護するミューテックスのロックを取得します。これにより、フォーク中にクリティカル セクション内にスレッドが存在しないことが保証されます。
  2. 子プロセスが作成された後、 fork() システムコールが戻る前に、 fork() を呼び出すスレッドのコンテキストで呼び出される関数。この関数は、親プロセスのミューテックスをロック解除できます。
  3. プロセスがフォークした場合に子プロセスのスレッドのコンテキストで呼び出される関数 - 子プロセスが作成された後、 fork() システムコールが戻る前に呼び出されます。その後、子プロセスはそのミューテックスのコピーをロック解除できます。

POSIX 標準では、fork() の後と exec() の前に許可されるシステム コールのタイプを、いわゆる async-signal-safe システム コールに制限しています。スレッドの作成は、async-signal-safe システム コールとして明示的にリストされていないため、POSIX では、子プロセスが fork() の後および exec() の前にスレッドを作成することを許可していません。皮肉なことに、ミューテックスのロック解除も非同期シグナルセーフ システム コールとして明示的にリストされておらず、fork() の意図が exec( ) - おそらく標準の見落としです。

于 2013-01-18T21:37:59.887 に答える