vforkまたはforkの子がexit()ではなく_exit()を呼び出す必要があるのはなぜですか?


12

のマニュアルページからvfork()

vfork()は、子がexecve(2)または_exit(2)を呼び出すまで親が一時停止されるという点でfork()とは異なります。子は、execve()が子によって発行されるまで、スタックを含むすべてのメモリを親と共有します。子は現在の関数から戻ったり、exit()を呼び出したりしてはなりませんが、_exit()を呼び出すことはできます。

なぜ子供が使用する必要があり_exit()、単純に呼び出すのではなくexit()?私は、これは両方に適用され願っていますvfork()fork()


回答:


11

以前見たvfork子プロセスが親プロセスのメモリにアクセスすることはできません。exitCライブラリ関数です(そのため、この関数はしばしばと書かれていますexit(3))。これは、Cストリーム(で宣言された関数によって開かれたファイル)のフラッシュとクローズstdio.h、およびで登録されたユーザー指定の関数の実行など、さまざまなクリーンアップタスクを実行しますatexit。これらすべてのタスクには、プロセスメモリの読み取りと書き込みが含まれます。

_exitクリーンアップせずに終了します。これは直接システムコールであり(そのため、と記述されています_exit(2))、通常、システムコール番号をプロセッサレジスタに配置し、特定のプロセッサ命令を実行することによって実装されます(システムコールハンドラに分岐します)。これはプロセスメモリにアクセスする必要がないため、後で実行しても安全ですvfork

以降fork、そのような制限はありません。親プロセスと子プロセスは完全に自律的になりました。


vforkは子プロセスが親のメモリにアクセスすることを許可しませんか?しかし、私は彼らが同じアドレス空間を共有すると思ったので、子供は親のアドレス空間にアクセスできます。その理解は間違っていましたか?
Sen

フォーク後は、そのような制限はありません。親プロセスと子プロセスは完全に自律的になりました。つまり、フォークの子からexit()を呼び出すことができますか?
セン

1
@セン:子は親のメモリにアクセスできません。カーネルがあなたを保護しないので、それを試してもうまくいくかもしれません。しかし、効果はあなたが意図したものではないかもしれません。たとえば、コンパイラが値をレジスタに残すと決定した場合、その値は親プロセスからは見えません。
Gilles「SO-邪悪なことをやめなさい」

@Sen:フォークの後で、exitまたはその他の関数を呼び出すことができます。すべてのプロセスはforkの後に始まります(Linuxでは、初期プロセスもinitカーネルによってforkされます)。
Gilles「SO-邪悪なことをやめ

3

exitによって登録された関数を呼び出すような追加のクリーンアップを実行し、atexitコピーされた部分の外部のデータにアクセスします。_exitカーネル内を除き、クリーンアップなしで直接syscallを実行します。


...そして、fork()はすべてをコピーするため、exit()を呼び出すことができ、現在の関数から確実に戻ることができることに注意してください。
derobert、2011年

3

子プロセスが終了したときにstdio(またはその他の)バッファーがフラッシュされないようにするために、子が_exit()を呼び出しています。子プロセスは親プロセスの正確なコピーを構成するので、子プロセスには、親が「stdout」または「stderr」にあるもの、つまり<stdio.h>からのバッファーがまだあります。親プロセスのバッファーがいっぱいになり、フラッシュされると、exit()を呼び出して1つは子プロセスのatexitハンドラーから、もう1つは親プロセスから呼び出すことで、二重の出力を取得できます(不都合な場合もあります)。

上記の回答はstdio.hの詳細に集中していることを理解していますが、上記の回答の1つが示すように、その考えはおそらく他のバッファリングされたI / Oにも引き継がれます。


1

exit():-I / Oストリームなどを閉じるなどのクリーンアップタスクを実行してから、カーネルに戻ります。 _exit():-カーネルに直接来る(クリーンアップタスクを実行しない)。

fork() :親と子の両方が異なるファイルテーブルを持っているため、子によって行われた変更は親の環境パラメーターに影響せず、その逆も同様です。

vfork():親と子の両方が同じファイルテーブルを使用するため、子によって行われた変更は親の環境パラメーターに影響します。たとえば、いくつかの変数はvar=10、現在はvar++子によって実行され、次に親を実行しますvar++。その結果は、親の出力でも確認できます。

私が言ったように、あなたが使用している場合exit()にはvfork()、すべてのI / Oがすでに閉じられています。したがって、親が正しく実行されても、すべての変数がフラッシュされ、すべてのストリームが閉じられるため、適切な出力を取得できません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.