プロセス制御 (Linux)

プロセスの作成

フォーク機能の紹介

fork 関数の機能は、既存のプロセス内に子プロセスを作成することです。

#include <unistd.h>
pid_t fork(void);

戻り値: 作成に失敗した場合は -1 が返され、作成が成功した場合、子プロセスは 0 を返し、親プロセスは子プロセスのプロセス ID を返します。簡単な例えができます: 父親は複数の子を持つことができますが、子は父親は 1 人だけなので、プロセスの作成後、子のプロセスをid父親に渡す必要があり、子プロセスは必要なgetpid()限り独自のプロセスを取得できます。id

ここに画像の説明を挿入
ここに画像の説明を挿入

プロセスが fork 関数を呼び出した後、オペレーティング システムは新しいメモリ ブロックとカーネル データ構造を子プロセスに割り当て、親プロセスのデータ構造の内容の一部を子プロセスにコピーし、子プロセスをプロセス リストに追加します。

fork関数の戻り値

fork関数にはなぜ2 つの戻り値があるのでしょうか? そして、戻った後、なぜ子プロセスの ID を親プロセスに割り当て、値 0 を子プロセスに割り当てるのでしょうか? if elseなぜ同時に同じ戻り値が成立するのでしょうか?
次に、機能を詳しく見てみましょう

まず、ユーザーがfork関数を使用すると、オペレーティング システムが関数の呼び出しを開始して、対応するタスクを完了します。

ここに画像の説明を挿入

関数fork()が準備完了return pid;すると、コア コードが実行され、子プロセスも作成され、オペレーティング システムの操作キューにスケジュールする準備が整います。したがって、実行前に親プロセスと子プロセスが分割されます。ステートメントはreturn pid;別々に実行できますreturn pid;; return の本質 書き込みです、子プロセスまたは親プロセスが最初に戻り、コピー時の書き込みのため、誰が最初に ID に書き込むか、同じ ID が 2 つの異なる内容を持つことになります、異なる内容と判断if elseに応じて一致します

フォークの一般的な使い方

  1. 親プロセスは自分自身をコピーして、親プロセスと子プロセスが異なるコードセグメントを同時に実行したいと考えています。
  2. 親プロセスは子プロセスに別のプログラムを実行させることを望んでいます

フォーク呼び出しが失敗した理由

  1. システム内のプロセスが多すぎます
  2. 実ユーザープロセス数が制限を超えています

プロセスが終了しました

プロセス終了シナリオ

  1. コードが実行され、結果は正しいです
  2. コードは最後まで実行されますが、エラーが発生します
  3. コードが異常終了する

プロセスを終了する一般的な方法

まず終了コードを紹介します。これまでに書かれたコードは最後に追加されますreturn 0が、なぜ他の数字ではなく数字 0 でなければならないのでしょうか? ? ?
プロセスが終了すると、プロセスの実行結果が正しいかどうかを示す、対応する終了コードが返されます。一般に、終了コードには対応するテキストの説明が必要です。終了コード: 0 は、プログラムが正常に実行されていることを意味します
0 特定の数字はさまざまなエラーを示します

プログラムは正常に終了します。
最新のプロセス終了コードecho $を確認する
ここに画像の説明を挿入

  1. 戻る 戻る

  2. 終了
    ここに画像の説明を挿入ここに画像の説明を挿入
    プログラムを呼び出すと、すぐには出力されずhello world2 秒後に出力され、終了コードもプログラムにexit(1)設定されたものと一致します。

  3. _exit
    ここに画像の説明を挿入
    ここに画像の説明を挿入
    プログラムを呼び出してもまったく出力されずhello world、終了コードも同じままです。

理由は次のとおりです。
exit はプロセスを終了し、バッファをアクティブにリフレッシュします。
_eixt はバッファをリフレッシュせずにプロセスを終了します。

2 つの違い: exit はライブラリ関数、_exit はシステム コールです。

ここに画像の説明を挿入

戻り関数

returnこれはプロセスを終了するより一般的な方法であり、実行はreturn n実行と同等です。exit(n)

プロセス待機中

処理待ちの必要性

  1. 子プロセスが終了すると、親プロセスはステータスを取得できなくなり、子プロセスがゾンビ状態になり、メモリ リークが発生します。
  2. プロセスがゾンビになった場合、OS は何もできません
  3. 親プロセスが子プロセスを作成する目的はタスクを完了することなので、子プロセスが実行されているかどうか、結果が正しいかどうか、正常に終了するかどうかを知る必要があります。
  4. 親プロセスは子プロセスのリソースを回収し、プロセス待機によって子プロセスの終了情報を取得します。

サブプロセスのステータスを取得する

プロセスの待機方法

  1. wait/waitpid、それぞれにstatusパラメータが、オペレーティング システムによって設定される出力パラメータです。
  2. NULLが渡された場合は、子プロセスの終了ステータス情報は関係ない(子プロセスはブロックされている)ことを意味します。
  3. オペレーティング システムは、このパラメータに従って、子プロセスの終了情報を親プロセスにフィードバックします。
  4. status単純に全体として見ることはできません。ビットマップは次のとおりです: 信号が 0 に等しい場合は正常終了を意味し、終了ステータスは終了コードです (ビットマップについては後ほど詳細に検討します)。

status&0x7Fプロセス終了情報、status >>8)&0xFFプロセス終了ステータスの取得

ここに画像の説明を挿入

waitメソッド

#include<sys/types.h>
#include<sys/wait.h>

pid_t wait(int*status);

戻り値: 成功した場合は、待機中のプロセスの ID を返します。失敗した場合は、-1 を返します。
パラメーター: 出力パラメーター、子プロセスの終了ステータスを取得します。気にしない場合は、NULL に設定できます。

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
子プロセスは最初の 10 秒間は実行されており、ステータスは ですS+。10 秒から 15 秒の間、​​子プロセスは終了し、ゾンビ プロセスになりますZ+。15 秒後、親プロセスはwait子プロセスのリソースを再利用します。

waitpid メソッド

#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid,int*status,int options);

戻り値: 成功した場合は、子プロセスの ID を返します。オプションが設定されているが、WNOHANG収集waitpidする終了した子プロセスがない場合は 0 を返します。失敗した場合は -1 を返し、errno は対応する値に設定されます。値が間違った表示になっている

パラメータ:
pid: 子プロセスID

status: WIFEXITED: 子プロセスが正常に終了した場合は true、プロセスが正常に終了したかどうかを確認します; WEXITSTATUS: WIFEXIT が 0 以外の場合、プロセスの終了コードを抽出し、プロセスの終了コードを確認します

options:
0 はデフォルトでブロッキング状態になります; WNOHANG(ノンブロッキング): pid で指定されたサブプロセスが終了していない場合、waitpd関数は待機せずに 0 を返します; プロセスが正常に終了した場合は、サブプロセスの ID が返されます

ここに画像の説明を挿入
ここに画像の説明を挿入

status子プロセス情報を取得するプロセス: 子プロセスが終了すると、終了ステータスと終了情報が PCB に保存されます。親プロセスのシステム コールは、子プロセスの終了ステータスを取得するwaitpidことによって、情報を終了します。status

ここに画像の説明を挿入

マクロでステータスを取得する

ここに画像の説明を挿入
ここに画像の説明を挿入

ブロッキングとノンブロッキング

ブロッキング: 親プロセスが子プロセスのリソースの取得を待機しているとき、子プロセスが終了していない場合、親プロセスは子プロセスの終了を待機しています; ノンブロッキング: 親プロセスが子プロセスのリソースの取得を待機しているとき、子プロセスが終了していない場合、親プロセスは子プロセスを常に待たずに他のプログラムを実行し、ポーリングを取ることができます

pid_t waitpid(pid_t pid,int*status,int options);このうち、option値が0の場合はブロッキング状態を表し、値が0optionの場合はWNOHANG

ブロッキング状態は上に示されており、子プロセス リソースの非ブロッキング取得は次に示されます。
ここに画像の説明を挿入
ここに画像の説明を挿入

waitpid戻り値: 0 に等しい場合、呼び出しは成功しますが、子プロセスは終了しません。0 より大きい場合、呼び出しは成功し、子プロセスも終了します。0 より小さい場合、呼び出しは失敗します。

  1. 子プロセスがすでに終了している場合、wait/waitpid呼び出されるとすぐに戻り、リソースを解放し、子プロセスの終了情報を取得します。
  2. いつでも呼び出されるとwait/waitpid、子プロセスが存在し、正常に実行されますが、プロセスがブロックされる可能性があります。
  3. 子プロセスが存在しない場合は、すぐにエラーが返されます。

プロセスプログラムの置き換え

交換原理

forkプログラムを実行するために子プロセスが作成された後、子プロセスexecは別のプログラム、つまり親プロセスとは異なるプログラムを実行するために関数を呼び出す必要があることがよくあります。プロセスが関数を呼び出すとき、作成された子プロセスexec、プログラムはメモリにロードされて実行されます。呼び出しによってexec新しいプロセスは作成されないため、execプロセスの ID は呼び出しの前後で変わりません。

プログラム置換の本質: 指定されたプログラムのコードとデータを指定された場所にロードし、親プロセスのデータとコードを上書きしない

ここに画像の説明を挿入

置換関数

から始まるexec6種類の関数があります。exec

int execl(const char *path, const char *arg, ...);

l: リスト、パラメータを 1 つずつexecl渡し

最初にプログラムを実行します。最初にプログラムを見つけてから実行する必要があります。実行方法も含めて、
pathプログラムのパスを示します。コマンド ライン パラメータと同様にarg、プログラムの実行方法を示します可変パラメータのリストを示します。 、最後のパラメータは次のようにする必要があります...NULL

ここに画像の説明を挿入
ここに画像の説明を挿入

実行結果では、最初の結果のみが出力されprintf、2 番目の結果は出力されません。なぜですか? もコードであり、2番目は置換関数の後にあるため、置換関数が実行されると、元のコードは完全に覆われ、新しいプログラムコードが起動して実行されるため、2番目は実行できません
printfexeclprintf

int execlp(const char *file, const char *arg, ...);

p:path、プログラムが配置されているパスを自動的に見つけることができ、実行するプログラムを入力するだけです

ここに画像の説明を挿入
![ここに画像の説明を挿入](https://img-blog.csdnimg.cn/7dda163e822444408419cc2419f2ecc4.png

1 つ目はls実行するプログラムを表し、2 つ目はls実行方法を表します。

int execv(const char *path, char *const argv[]);

v: ベクトル、変数パラメータを使用する代わりに、すべての実行可能なパラメータを配列に入れて均一に渡すことができます。

ここに画像の説明を挿入

ここに画像の説明を挿入

int execvp(const char *file, char *const argv[]);

実行するプログラムとその実行方法を直接入力します。

ここに画像の説明を挿入
ここに画像の説明を挿入

ここまででシステムコマンドが実行できましたので、作成したプログラムを実行してみましょう。

ここに画像の説明を挿入

自分で書いたプログラム:

ここに画像の説明を挿入

操作結果:
ここに画像の説明を挿入

実行結果によると、呼び出しは非常に成功しているため、置換関数を使用して任意の言語でプログラムを呼び出すことができます。

int execle(const char *path, const char *arg,
                    ..., char * const envp[]);

e: カスタム環境変数

カスタム環境変数を追加せずに最初に試してください

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

上記は 2 つのシステムで環境変数を取得する簡単な方法ですが、環境変数をカスタマイズしたい場合はどうすればよいですか? ? ?

最初に機能を導入します:システムで指定されている環境変数テーブルputenv
ここに画像の説明を挿入
に環境変数を追加します。カスタム環境変数の操作は次のとおりです。environ

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

execle環境変数の取得が可能 上記置換関数でも同様に環境変数の取得が可能であり、仮想アドレス空間には環境変数パラメータが存在し、子プロセスはアドレス空間を通じて環境変数を取得することができます。

execleの引数リストは、mian関数

ここに画像の説明を挿入

mainこれは関数でもあり、呼び出してパラメータとして渡す必要があり、execlプログラムはメモリにロードされるため、プログラムの実行順序は、最初にロードし、次に実行します。

プログラム置換機能の本質はプログラムをメモリにロードすることであり、ロード作業は Linux exec* ローダによって行われます。

機能説明

  1. 置換関数が正常に呼び出された場合、新しいプログラムがロードされ、リターンせずにスタートアップ コードから実行されます。
  2. 置換が失敗した場合は -1 を返します
  3. 置換関数、失敗戻り値のみ、成功戻り値なし

おすすめ

転載: blog.csdn.net/qq_68006585/article/details/129845290