Linuxでfork-execメカニズムがどのように使用されているかを把握しようとしています。いくつかのWebページが私を混乱させ始めるまで、計画通りにすべてが進行していました。
子プロセスは、単純な_exit()
またはexit()
からの通常の戻り値の代わりに、厳密にmain()
を使用する必要があると言われています。
私が知っているように、Linux Shellはすべての外部コマンドをfork-execします。上記で述べたことが真実であると仮定すると、結論は、これらの外部コマンドもLinux Shell内で発生する他の実行も通常のリターンを行えないということです!
ウィキペディアと他のいくつかのウェブページは、_exit()
を使用して、stdioバッファの二重フラッシュが発生する可能性がある間、親の一時ファイルの削除を引き起こす子プロセスを防ぐ必要があると主張しています。前者は理解していますが、バッファのダブルフラッシュがLinuxシステムにどのように有害であるかはわかりません。
私はこれに1日を費やしました...説明をありがとう。
_exit
(またはその同義語_Exit
)を使用して、exec
が失敗したときに子プログラムを中止する必要があります。プロセスは、そのatexit
ハンドラーの呼び出し、シグナルハンドラーの呼び出し、および/またはバッファーのフラッシュによって、親プロセスの外部データ(ファイル)に干渉する場合があります。
同じ理由で、exec
を実行しない子プロセスでも_exit
を使用する必要がありますが、これらはまれです。
その他の場合はすべて、exit
を使用します。部分的に自分自身に注意したように、Unix/Linuxの every プロセス(init
を除く)は別のプロセスの子なので、すべてで_exit
を使用します子プロセスは、exit
がinit
の外では役に立たないことを意味します。
switch (fork()) {
case 0:
// we're the child
execlp("some", "program", NULL);
_exit(1); // <-- HERE
case -1:
// error, no fork done ...
default:
// we're the parent ...
}
exit()
はioバッファをフラッシュし、atexit()
によって登録された実行関数のような他のことを行います。 exit()
は_end( )
を呼び出します
_exit()
は、それを行わずにプロセスを終了します。たとえば、デーモンを作成するときに、親プロセスから_exit()
を呼び出します。
main()
が関数であることに気づいたことがありますか?そもそも何と言ったのだろうか? acプログラムが実行しているシェルを実行すると、実行する「exec」システムコールへのパスが提供され、制御がカーネルに渡されます。カーネルはすべての実行可能ファイル_start()
の起動関数を呼び出し、main()
、main()
が返されたときに_end()
を呼び出しますCの一部の実装では、_end()
と_start()
にわずかに異なる名前を使用します。 。
exit()
および_exit()
invoke _end()
通常-main()
ごとに、exit()
呼び出しが1つだけ必要です。 (またはmain()
の終わりに戻ります)
exit()は、従来のCライブラリを使用して、_exit()の上部にあります。
違いがあります:
_exit()はstdioバッファーをフラッシュしませんが、exit()は終了前にstdioバッファーをフラッシュします。
_exit()はクリーンアッププロセスを実行できませんが、exit()は、プログラムが存在する前に何らかのクリーンアッププロセスが必要な場合、何らかの関数(on_exitまたはat_exit)で登録できます。
exit(status)は、単に終了ステータスを_exit(status)に渡します。 fork()を実行するときはいつでも、子と親の間で、1つは_exit()を使用し、もう1つはexit()を使用することをお勧めします。
fork()
の子ブランチでは、exit()
を使用することは通常正しくありません。stdioバッファーがフラッシュされる可能性があるためですtwice、および一時ファイルが予期せず削除されています。