[Linux オペレーティング システム] Linux プロセスの詳細な調査: 作成、共有、管理

プロセスの作成は、Linux システム プログラミングにおける重要な概念の 1 つです。このセクションでは、プロセスの作成、プロセス ID と親プロセス ID の取得、プロセス共有、exec 関数ファミリー、wait と waitpid などの関連コンテンツを紹介します。
ここに画像の説明を挿入


1. プロセスの作成

Linux システムでは、fork()システム コールを使用してプロセスが作成されます。fork()システム コールは現在のプロセスと同一の子プロセスを作成し、子プロセスはコード、データ、ファイル記述子を含む親プロセスのすべてのリソースをコピーします。


1.1 関数プロトタイプと戻り値

fork()関数のプロトタイプは次のとおりです。

#include <unistd.h>

pid_t fork(void);

fork()この関数にはパラメータがなく、戻り値は のpid_t整数型です。具体的な説明は以下の通りです。

  • 呼び出しが成功すると、fork()関数は親プロセスでは子プロセスの PID (子プロセス ID) を返し、子プロセスでは 0 を返します。
  • 呼び出しが失敗した場合、fork()関数は -1 を返し、errnoエラーの種類を示すように設定されます。

1.2 機能例

コード例は次のとおりです。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
    
    
    pid_t pid = fork();
    if (pid == -1) {
    
    
        printf("Failed to fork a new process.\n");
        return 1;
    } else if (pid == 0) {
    
    
        printf("This is the child process.\n");
    } else {
    
    
        printf("This is the parent process.\n");
    }
    return 0;
}

上記のコードでは、fork()システム コールは親プロセスと子プロセスのそれぞれで 2 回返されます。戻り値を判断することで、親プロセスと子プロセスを区別し、異なるコード ロジックを実行できます。



2. プロセスIDと親プロセスIDを取得する

Linux システムでは、getpid()getppid()システム コールを使用して、現在のプロセスの ID と親プロセスの ID を取得できます。


2.1 関数のプロトタイプと戻り値

getpid()getppid()関数のプロトタイプは次のとおりです

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

pid_t getpid(void);
pid_t getppid(void);

これらの関数は両方ともパラメータをとらず、どちらもpid_t型の整数を返します。具体的な説明は以下の通りです。

  • getpid()この関数は、呼び出し元プロセスのプロセス ID (PID) を返します。
  • getppid()この関数は、呼び出しプロセスの親プロセスのプロセス ID (PPID) を返します。

2.2 機能例

コード例は次のとおりです。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
    
    
    pid_t pid = getpid();
    pid_t ppid = getppid();
    printf("Process ID: %d\n", pid);
    printf("Parent Process ID: %d\n", ppid);
    return 0;
}


3. 実行関数ファミリー

Linux システムでは、exec()関数ファミリーを使用して現在のプロセスを新しいプログラムに置き換えることができます。exec()関数ファミリーにはexecl()execv()、 、execle()execve()およびその他の関数が含まれます。これらの関数は、さまざまなパラメータ形式に従ってさまざまな置換を実行できます。


3.1exec()関数ファミリーの共通メンバー:

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

    • 引数pathは、実行する新しいプログラムへのパスです。
    • argumentargは、新しいプログラムの最初の引数を表す文字列です。
    • 可変引数リストは、新しいプログラムの追加引数であり、NULLで終わる必要があります。
    • 関数が正常に実行されても戻りませんが、戻った場合は実行が失敗したことを意味します。

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

    • 引数pathは、実行する新しいプログラムへのパスです。
    • argument はargv、新しいプログラムの引数リストを表す文字列の配列であり、最後の要素は でなければなりませんNULL
    • 関数が正常に実行されても戻りませんが、戻った場合は実行が失敗したことを意味します。

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

    • 引数pathは、実行する新しいプログラムへのパスです。
    • argumentargは、新しいプログラムの最初の引数を表す文字列です。
    • 可変引数リストは、新しいプログラムの追加引数であり、NULLで終わる必要があります。
    • 引数はenvp、新しいプログラムの環境変数のリストを表す文字列の配列であり、最後の要素は でなければなりませんNULL
    • 関数が正常に実行されても戻りませんが、戻った場合は実行が失敗したことを意味します。

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

    • 引数はfile、実行する新しいプログラムのファイル名です。
    • argument はargv、新しいプログラムの引数リストを表す文字列の配列であり、最後の要素は でなければなりませんNULL
    • 関数が正常に実行されても戻りませんが、戻った場合は実行が失敗したことを意味します。

これらの関数は、正常に実行されても戻りませんが、現在のプロセスを新しいプログラムに直接置き換えます。戻ってきた場合は実行が失敗したことを意味し、戻り値によってエラーの種類を判断できます。

exec()関数ファミリを使用すると、現在のプロセスに新しいプログラムをロードして実行することができ、プログラムの動的な切り替えや機能拡張を実現できます。一般に、exec()関数ファミリーは、fork()関数を呼び出して子プロセスを作成し、子プロセスのコードとデータを置き換えた後に使用されます。


3.2 機能例

コード例は次のとおりです。

#include <stdio.h>
#include <unistd.h>

int main() {
    
    
    printf("Before exec()\n");
    execl("/bin/ls", "ls", "-l", NULL);
    printf("After exec()\n");
    return 0;
}

上記のコードでは、execl()関数は現在のプロセスをls -lコマンドに置き換えます。execl()関数の最初の引数は実行するプログラムのパスで、後続の引数は新しいプログラムに渡されるコマンドライン引数です。



4.wait和waitpid

Linux システムでは、親プロセスはwait()またはwaitpid()システム コールを使用して、子プロセスの終了を待つことができます。これらのシステム コールは、子プロセスが終了するまで親プロセスの実行をブロックします。


4.1 機能説明

wait()と はwaitpid()、子プロセスの終了を待ち、子プロセスの終了ステータスを取得する関数です。

  1. pid_t wait(int *status);

    • この関数は、子プロセスが終了するまで現在のプロセスを一時停止します。
    • 子プロセスの終了まで正常に待機した場合、関数は子プロセスのプロセス ID を返します。
    • このパラメータは、status子プロセスの終了ステータス情報を格納するために使用される整数へのポインタです。
    • 呼び出しが失敗した場合、関数は -1 を返します。

  2. pid_t waitpid(pid_t pid, int *status, int options);

    • この関数は、指定された子プロセスが終了するまで現在のプロセスを一時停止します。
    • パラメータpid待機する子プロセスのプロセス ID を指定します。
    • このパラメータは、status子プロセスの終了ステータス情報を格納するために使用される整数へのポインタです。
    • パラメーターは、options待機するオプションを指定する整数値です。
    • 呼び出しが失敗した場合、関数は -1 を返します。

wait()andwaitpid()関数の戻り値は、子プロセスのプロセス ID、または呼び出しが失敗した場合は -1 です。status子プロセスの終了ステータス情報は、終了コード、終了シグナルなどを含むパラメータを通じて取得できます。

waitpid()関数は関数よりもwait()柔軟性が高く、パラメーターpidとを使用してoptions待機中のサブプロセスを制御できます。

その中で、pidの値は次のとおりです。

  • -1: 子プロセスを待ちます。
  • 0: 現在のプロセスと同じプロセス グループ ID を持つ子プロセスを待ちます。
  • 特定の子プロセス ID: 指定された子プロセスを待ちます。

optionsパラメーターでは、ビットマスクの形式で複数のオプションを指定できます。一般的に使用されるオプションは次のとおりです。

  • WNOHANG: ノンブロッキング モード。子プロセスが終了しない場合は、すぐに戻ります。
  • WUNTRACED: 停止したサブプロセスのステータスも返します。
  • WCONTINUED: 実行を継続している子プロセスのステータスも返します。

wait()またwaitpid()、関数を使用して、子プロセスの終了ステータスを処理したり、子プロセスのリソースを解放したり、プロセス間同期を実行したりできます。これら 2 つの関数を使用する場合は、エラー状態の処理とゾンビ プロセスの生成の回避に注意する必要があります。


4.2 機能例

コード例は次のとおりです。

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

int main() {
    
    
    pid_t pid = fork();
    if (pid == -1) {
    
    
        printf("Failed to fork a new process.\n");
        return 1;
    } else if (pid == 0) {
    
    
        printf("This is the child process.\n");
    } else {
    
    
        wait(NULL);
        printf("This is the parent process.\n");
    }
    return 0;
}

上記のコードでは、親プロセスはwait(NULL)システム コールを使用して子プロセスの終了を待ちます。wait()システムコールは、子プロセスが終了するまで親プロセスの実行をブロックします。



要約する

  1. fork()機能: 子プロセスの作成に使用され、異なる戻り値は異なるプロセスでの実行を示します。
  2. exec()関数ファミリー: 現在のプロセスに新しいプログラムをロードして実行するために使用され、プログラムの動的な切り替えと機能拡張を実現できます。
    • execl(): 変数パラメータの形式を受け入れ、パラメータは文字列の形式で渡されます。
    • execle(): 変数パラメータの形式を受け入れ、同時に環境変数を渡します。
    • execvp(): パラメータの配列の形式を受け入れ、パラメータは文字列配列の形式で渡されます。
  3. wait()機能waitpid(): 子プロセスの終了を待ち、子プロセスの終了ステータスを取得するために使用されます。
    • wait(): 子プロセスが終了するまで待ちます。
    • waitpid(): 待機する子プロセスを指定できます。
    • 子プロセスの終了ステータス情報は、パラメータを通じて取得できますstatus
    • ノンブロッキング モードなどのパラメータを通じてoptions待機オプションを制御できます。
    • エラー状態を処理し、ゾンビ プロセスの生成を回避するには注意が必要です。

これらの関数とシステム コールを使用して、プロセスを作成、実行し、プロセス間の同期とコラボレーションが達成されるまで待機することができます。これらの機能により、動的なプロセス切り替え、機能拡張、リソース解放が実現できます。同時に、ゾンビ プロセスやリソース リークを避けるために、エラー状態の処理に注意を払う必要があります。

おすすめ

転載: blog.csdn.net/Goforyouqp/article/details/132276890