Linux プロセス作成コマンド: 1. fork コマンドは、既存のプロセスから新しいプロセスを作成できます。新しいプロセスは子プロセスで、元のプロセスは親プロセスです。子プロセスはリソースを完全にコピーします。親プロセスの。 2. vfork コマンドを使用すると、作成された子プロセスは親プロセスとアドレス空間を共有します。これは、子プロセスが完全に親プロセスのアドレス空間で実行されることを意味します。 3. clone コマンドは、親プロセスのリソースを子プロセスに選択的にコピーでき、コピーされなかったデータ構造は、ポインタのコピーを通じて子プロセスによって共有されます。
#このチュートリアルの動作環境: linux7.3 システム、Dell G3 コンピューター。
Linux システムでプロセスを作成するために使用できるコマンドは、fork、vfork、clone の 3 つです。
fork
fork がプロセスを作成すると、子プロセスは親プロセスのリソースを完全にコピーするだけです。コピーされた子プロセスには独自の task_struct 構造体と pid があり、ただし、親プロセスの他のすべてのリソースをコピーします。たとえば、親プロセスで 5 つのファイルが開いている場合、子プロセスでも 5 つのファイルが開いており、これらのファイルの現在の読み取りおよび書き込みポインタも同じ場所で停止します。したがって、このステップで行うことはコピーです。このようにして得られた子プロセスは、親プロセスから独立しており、同時実行性も良好ですが、両者間の通信にはパイプや共有メモリなどの特殊な通信機構が必要であり、さらにフォークによる子プロセスの作成も必要となります。 、上記の説明を使用する必要があります。各リソースのコピーを作成します。この観点から見ると、fork は非常に高価なシステム コールです。これらのオーバーヘッドはすべての場合に必要というわけではありません。たとえば、プロセスが子プロセスをフォークした後、その子プロセスは exec を呼び出して別の実行可能ファイルを実行するだけです。フォーク処理中の仮想メモリ空間のコピーは冗長処理となります。しかし、Linux は現在コピーオンライト (COW コピーオンライト) テクノロジを採用しているため、オーバーヘッドを削減するために、フォークは実際には最初に 2 つの異なるコピーを作成しません。同じ。コピーオンライトでは、データの実際のコピーが延期されます。後で書き込みが発生した場合は、親と子のデータに不整合があることを意味するため、コピー アクションが発生し、各プロセスが独自のコピーを取得するため、システム コールのオーバーヘッドが軽減されます。したがって、コピーオンライトでは、vfork の実装はほとんど意味がありません。
fork() 呼び出しは、一度実行されると 2 つの値を返します。親プロセスの場合、fork 関数はサブプログラムのプロセス番号を返しますが、サブプログラムの場合、fork 関数は 0 を返します。これが本質です。 2 回返す関数。
フォーク後、子プロセスと親プロセスの両方は、フォーク呼び出し後の命令の実行を継続します。子プロセスは親プロセスのコピーです。親プロセスのデータ スペース、ヒープ、スタックのコピーを取得します。これらはコピーです。親プロセスと子プロセスはメモリのこの部分を共有しません。つまり、親プロセス内の同じ名前の変数を子プロセスが変更しても、親プロセスの値には影響しません。しかし、父プロセスと息子プロセスは何かを共有しています。それは単にプログラムのテキストセクションです。テキスト セグメントには CPU によって実行される機械語命令が格納され、通常は読み取り専用です。
vfork
vfork システム コールは fork とは異なり、vfork で作成された子プロセスは親プロセスとアドレス空間を共有します。アドレス空間では、この時点で子プロセスが変数を変更すると、親プロセスに影響を与えます。
したがって、上記の例で vfork() を使用すると、2 回出力される a と b の値は同じになり、アドレスも同じになります。
ただし、ここで注意すべき点は、vfork() で作成された子プロセスは終了するために明示的に exit() を呼び出す必要があるということです。そうしないと、子プロセスは終了できず、この状況は fork では存在しません。 ()。
Vfork は、親プロセスでは子プロセスのプロセス番号を返し、子プロセスでは 0 を返します。
vfork を使用して子プロセスを作成した後、子プロセスが exec (exec、新しい実行可能ファイルをアドレス空間にロードして実行します) を呼び出すか終了するまで、親プロセスはブロックされます。 vfork の利点は、子プロセスの作成後、多くの場合、exec を呼び出すだけで別のプログラムを実行できることです。これは、親プロセスのアドレス空間への参照がないため、アドレス空間のコピーが冗長であるためです。 , そのため、vfork を通じて共有されます メモリにより、不要なオーバーヘッドを削減できます。
clone
システム コールの fork() と vfork() にはパラメータがありませんが、clone() にはパラメータがあります。 fork() はすべてコピー、vfork() はメモリ共有、clone() は親プロセスのリソースを子プロセスに選択的にコピーでき、コピーされなかったデータ構造はポインタコピーにより子プロセスで共有されます。具体的には、どのリソースを子プロセスにコピーするかは、パラメータ リストの clone_flags によって決定されます。さらに、 clone() は子プロセスの pid を返します。
fork コマンド (プロセス作成) の詳細については、以下をご覧ください。
詳細な fork 関数
fork 関数は、Linux の非常に重要な関数です。既存のプロセスからプロセスを作成します。プロセス、新しいプロセス。新しいプロセスは子プロセスであり、元のプロセスは親プロセスです。
フォーク関数の戻り値:
- 子プロセスのpidを親プロセスに返す
- 子プロセスに0を返す
次にfork関数()を使ってみましょう。例として
コンパイルして実行してみましょう:
fork の一般的な使用法
- #親プロセスは、親プロセスと子プロセスが異なるコード セグメントを同時に実行できるように、自分自身をコピーしようとしています。たとえば、親プロセスはクライアント要求を待機し、要求を処理するために子プロセスを生成します。
- プロセスが別のプログラムを実行しようとしています。たとえば、子プロセスがフォークから戻った後、exec 関数を呼び出します。
fork() の作成子プロセス、オペレーティング システムはどのような操作を実行しますか?#フォーク呼び出しが失敗した理由
#システム内のプロセスが多すぎますfork 関数の使用法を確認した後、次のトピックを学習しましょう:
- 実際のユーザー プロセス数が制限を超えています
プロセスはフォークを呼び出します。制御がカーネル内のフォーク コードに移されると、カーネルは次の操作を実行します:
新しいものを割り当てるメモリ ブロックとカーネル データ構造を子プロセスに渡します。
- 親プロセスのデータ構造の内容の一部を子プロセスにコピーします。
- 子プロセスをシステム プロセス リストに追加します。
- fork が戻り、スケジューラーのスケジューリングを開始します。
親プロセスが fork の前 (before) にコードを実行した後、fork を呼び出して子プロセスを作成し、2 つの実行父と子のストリームは別々に実行されます。注:
fork の後、誰が最初に実行するかは、スケジューラ によって完全に決定されます。
ここで別の質問があります。フォーク後、親プロセスと子プロセスの間でコードは共有されますか、それともすべてのコードが共有されますか? 子プロセスが常に対応するコードを実行するのはなぜですか?フォークの後は正確ですか?
#回答: CPU はプロセスが実行されている場所を追跡するため、すべてのコードが共有されます。#子プロセスが作成されると、オペレーティング システムは対応するデータ構造を子プロセスに割り当て、プロセスが独立しているため、子プロセスは独立して実行されます。コードがアセンブルされると、多数のコード行が作成され、メモリにロードされた後、コードの各行に対応するアドレスが割り当てられます。
- プロセスはいつでも中断される可能性がある(完了しない可能性がある)ため、次回実行を継続するときは、前の位置(プログラムまたはメイン関数の先頭ではない)から継続する必要があります。これには、CPU が現在のプロセスの実行位置をリアルタイムで記録する必要があります。
- したがって、CPU には、現在のプロセスの実行位置を記録するための対応するレジスタ データがあります。このレジスタは EIP と呼ばれ、pc (ポイント コード プログラム カウンタ) とも呼ばれ、次のプロセスを記録するために使用されます。実行中のコードの行 コードのアドレス (コンテキスト データ)。
- 子プロセスが作成されると、その EIP が変更されます。このとき、子プロセスはEIPに保存されているデータを実行すべきコードとみなします。
理論的には、子プロセスにも独自のコードとデータが必要ですが、一般的に、子プロセスの作成時に読み込みプロセスはなく、子プロセス自体は独自のコードとデータを持ちません。
したがって、子プロセスは親プロセスのコードとデータのみを「使用」でき、コードは読み取り専用であり、親子共有は競合しません。一方、データは変更される可能性があるため、変更する必要があります。別れる。
現時点では、オペレーティング システムはコピーオンライト戦略を採用しています。
コピーオンライトOS がコピーオンライト テクノロジを使用して親と子を分離するのはなぜですかプロセス
書き込み時のコピーは、メモリの効率的な使用の表れです。
#拡張知識: プロセスの終了と- システムの運用効率が向上します。
- OS は、コードが実行される前にどのスペースがアクセスされるかを予測できません。
プロセスが終了すると、オペレーティング システムは、プロセスによって要求された関連するカーネル データ構造と対応するコード データを解放します。その本質は、システム リソースを解放することです。
1. プロセス終了コード
プロセス終了の一般的な方法:
コードを実行すると、結果は正しくなります。 コードの実行後の結果は正しくありません。main関数の戻り値がプロセスの終了コードになるC言語で学習したmain関数の戻り値について。その意味は、上位プロセスに戻ってプロセスの実行結果を評価することです。
- コードの実行が完了せず、プログラムがクラッシュしました。
- 最初のケースと 2 番目のケースは、プロセスの終了コードによって明確に区別できます。
次に、簡単な C プログラムを作成します。
次に、 echo $? を通じて最新のプロセスの終了コードを取得できます。
プロセスの戻り値には、0 と 0 以外の 2 つの状況があります。0 はプログラムが正常に実行され、結果が正しいことを意味し、0 以外は次のことを意味します。プログラムは正常に実行されますが、結果が正しくありません。ゼロ値は無数にあり、ゼロ以外の値が異なると異なるエラーを表すことができるため、エラーの原因を特定しやすくなります。
一般的なエラー メッセージは何ですか?
strerror を使用して出力できます。
結果は次のようになります。
Linux では、合計 133 個のエラー コードがあることがわかりました。
もちろん、プログラムがクラッシュした場合、終了コードは意味がありません。
ご存知のとおり、Linux は C 言語で書かれており、コマンドは基本的に C 言語プログラムであるため、単純に ls コマンドを例として使用できます
終了コード 2 に対応するエラー メッセージ:
2. exit と _exit
return ステートメントを使用して、exit 関数と _exit 関数を呼び出すこともできます
exit 関数:
# _exit 関数:
これら 2 つの関数には多くの違いがあります。最初に小さな例を挙げましょう:
次に、printf を使用してメッセージを出力し、3 秒間スリープしてから、 exit して終了し、結果を観察します
\n を追加したため、\n を追加するとバッファが更新され、印刷した内容が画面に表示されます。
\n を指定しない場合は、結果を観察します:
見つかりました: がないためです。 \n, そのため、スリープ前に printf の内容は出力されませんが、exit を呼び出した後、バッファの内容が更新されて画面に出力されます。
次に、_exit 関数を使用します。
実行可能ファイル b を実行します。
Discover Nothing is echo $? を使用して最近のプロセス終了コードを出力し、ファイル b が実際に実行されていることを確認します。
これは、exit がライブラリ関数であり、_exit がシステム コールであり、プロセスの終了時にバッファの内容を更新しないことを示しています。
この時点で結論を導き出すことができます:
printf データは「バッファ」に保存され、exit でそれを更新でき、システム コール インターフェイス_exit では更新できません。したがって、バッファはオペレーティング システム内に存在するのではなく、C 標準ライブラリによって維持される必要があります。
関連する推奨事項: 「Linux ビデオ チュートリアル 」
以上がLinuxのプロセス作成コマンドとは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。