この記事では、プロセス ID の簡単な説明から始めて、すぐに実践的な側面に移ります。ここでは、fork()、execv()、wait() などのプロセス関連の C 関数について説明します。
Linux プロセス シリーズ:パート 1、パート 2、パート 3 (この記事)。
プロセス ID
プロセス ID は、プロセスに関連付けられた負でない数値であるプロセス ID です。これらの番号は、システムで実行されているプロセス全体で一意です。
プロセス ID のこの一意性は、いくつかの一意のファイル名を作成するためにプロセスによって使用されることがあります。プロセスがシステムから終了すると、そのプロセス ID が再利用できるようになります。
ただし、プロセス ID を再利用できるようになるまでには、特定の遅延が発生します。これは、現在終了している前のプロセスに関連付けられていたプロセス ID が、ファイル名などの形式で使用されている可能性があるためです。そのため、同じプロセス ID を再利用する前に遅延が追加されます。
プロセス ID 1 は init プロセス用です。これは、システムの起動後に開始される最初のプロセスです。
init プロセスのプログラム ファイルは、/etc/init または /sbin/init にあります。 init プロセスはユーザー レベルのプロセスですが、root 権限で実行され、カーネルがブートストラップされた後の状態にシステムを移行する責任があります。特定の状態を達成するために init プロセスによって読み取られる起動ファイルは、
- /etc/rc*.d
- /etc/init.d
- /etc/inittab
プロセス ID 0 は、システムのスケジューラです。これは、システム内で行われるすべてのプロセス スケジューリングを担当するカーネル レベルのプロセスです。
プロセス制御機能
fork() 関数
C でデーモン プロセスを作成する記事で既に説明したように、fork 関数は、プロセス内からプロセスを作成するために使用されます。
fork() によって作成された結果の新しいプロセスは子プロセスとして知られ、元のプロセス (fork() が呼び出されたプロセス) は親プロセスになります。
関数 fork() は (親プロセスで) 1 回呼び出されますが、2 回返されます。 1回目は親プロセスに戻り、2回目は子プロセスに戻ります。親と子の実行順序は、プロセスのスケジューリング アルゴリズムによって異なる場合があることに注意してください。 fork 関数が プロセス作成 で使用されていることがわかります .
fork() の署名は :
pid_t fork(void);
関数の exec ファミリー
プロセスの作成に一般的に使用される別の関数セットは、exec です。 関数のファミリー。これらの関数は主に、プロセス内から既存のバイナリを実行する必要がある場合に使用されます。
たとえば、プロセス内から「whoami」コマンドを実行するとします。このようなシナリオでは、exec() 関数またはこのファミリーの他のメンバーが使用されます。ここで注目すべき点は、関数の exec ファミリのいずれかを呼び出すと、現在のプロセス イメージが新しいプロセス イメージに置き換えられることです。
このファミリーの一般的なメンバーは execv() 関数です。その署名は次のとおりです:
int execv(const char *path, char *const argv[]);
注意 :このファミリーの他のメンバーについては、exec のマンページを参照してください。
wait() および waitpid() 関数
子プロセスが終了または状態を変更したときに、親プロセスが子プロセスの状態の変更または終了ステータスを認識しなければならない特定の状況があります。その場合、 wait() のような関数 これらの関数を使用して、親が子プロセスの状態の変化を照会できる親プロセスによって使用されます。
wait() の署名は :
pid_t wait(int *status);
親プロセスに複数の子プロセスがある場合、関数 waitpid() があります 親プロセスが特定の子の変更状態を照会するために使用できるもの。
waitpid() のシグネチャは次のとおりです:
pid_t waitpid(pid_t pid, int *status, int options);
デフォルトでは、waitpid() は終了した子のみを待機しますが、この動作はオプション引数を介して変更できます。以下で説明します。
pid の値は次のとおりです。
- <-1 :プロセス グループ ID が pid の絶対値と等しい子プロセスを待ちます。
- -1 :子プロセスを待ちます。
- 0 :呼び出しプロセスのプロセス グループ ID と同じプロセス グループ ID を持つ子プロセスを待ちます。
- > 0 :プロセス ID が pid の値と等しい子プロセスを待ちます。
options の値は、以下の定数の 0 個以上の OR です:
- WNOHANG :子が終了していない場合はすぐに戻ります。
- WUNTRACED :子供が停止した場合も戻ります。このオプションが指定されていない場合でも、停止したトレースされた子のステータスが提供されます。
- WCONTINUED :停止した子が SIGCONT の配信によって再開された場合にも返されます。
waitpid() の詳細については、この関数の man ページを参照してください。
プログラム例
上記のすべてのタイプの関数を利用した例を次に示します。
#include <unistd.h> #include <sys/types.h> #include <errno.h> #include <stdio.h> #include <sys/wait.h> #include <stdlib.h> int global; /* In BSS segement, will automatically be assigned '0'*/ int main() { pid_t child_pid; int status; int local = 0; /* now create new process */ child_pid = fork(); if (child_pid >= 0) /* fork succeeded */ { if (child_pid == 0) /* fork() returns 0 for the child process */ { printf("child process!\n"); // Increment the local and global variables local++; global++; printf("child PID = %d, parent pid = %d\n", getpid(), getppid()); printf("\n child's local = %d, child's global = %d\n",local,global); char *cmd[] = {"whoami",(char*)0}; return execv("/usr/bin/",cmd); // call whoami command } else /* parent process */ { printf("parent process!\n"); printf("parent PID = %d, child pid = %d\n", getpid(), child_pid); wait(&status); /* wait for child to exit, and store child's exit status */ printf("Child exit code: %d\n", WEXITSTATUS(status)); //The change in local and global variable in child process should not reflect here in parent process. printf("\n Parent'z local = %d, parent's global = %d\n",local,global); printf("Parent says bye!\n"); exit(0); /* parent exits */ } } else /* failure */ { perror("fork"); exit(0); } }
上記のコードでは、次のようなプログラムを作成しようとしました:
- fork() API を使用して子プロセスを作成します
- ローカル変数とグローバル変数を使用して、fork が親プロセスのコピーを作成し、子プロセスには独自の変数のコピーがあることを証明します。
- execv API を使用して「whoami」コマンドを呼び出します。
- wait() API を使用して、親の子の終了ステータスを取得します。この API は、子が終了するか状態が変わるまで、親の実行を保留することに注意してください。
ここで、上記のプログラムを実行すると、次の出力が生成されます:
$ ./fork parent process! parent PID = 3184, child pid = 3185 child process! child PID = 3185, parent pid = 3184 child's local = 1, child's global = 1 himanshu Child exit code: 0 Parent'z local = 0, parent's global = 0 Parent says bye!