C言語のwait関数完全ガイド!初心者でも分かる7つのステップ

C言語のwait関数の使い方を説明する図解 C言語

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

このサービスはSSPによる協力の下、運営されています。

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

C言語のwait関数は、特定のプロセスが終了するのを待つための重要な関数です。

この記事では、wait関数について初心者でも理解できるように、基本から応用までを7つのステップで詳しく解説します。

一緒に学んでいきましょう。

●C言語とは

C言語は、コンピュータの基本的な動作を直接制御することができる言語で、UNIXオペレーティングシステムの開発にも使われました。

そのため、C言語にはOSレベルのプロセス制御機能が豊富に備わっています。

ここで紹介するwait関数もその一つで、子プロセスが終了するのを待つ機能を提供しています。

●wait関数の基本

C言語のwait関数は、子プロセスが終了するまで親プロセスをブロックするという特性を持っています。

つまり、子プロセスがまだ動作中の場合、その終了を待つため親プロセスは一時停止します。

これは、例えば複数のプロセスが一定の順序で実行されるべき状況で有用です。

子プロセスの計算結果を親プロセスが必要とする場合などにwait関数を利用します。

●wait関数の使い方

wait関数はシンプルな関数で、その基本的な使い方は次のようになります。

○サンプルコード1:基本的なwait関数の使い方

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // 子プロセスの処理
        printf("これは子プロセスです。\n");
    } else {
        // 親プロセスが子プロセスの終了を待つ
        wait(NULL);
        printf("これは親プロセスで、子プロセスの終了を待ちました。\n");
    }

    return 0;
}

このコードではfork関数を使って新たな子プロセスを生成しています。

そして、親プロセスではwait関数を呼び出して子プロセスの終了を待ちます。

子プロセスが終了すると、親プロセスが再び動き出します。

○サンプルコード2:子プロセスの終了を待つ

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

int main() {
    pid_t pid = fork();
    int status;

    if (pid == 0) {
        printf("これは子プロセスです。\n");
    } else {
        wait(&status);
        if (WIFEXITED(status)) {
            printf("子プロセスは正常に終了しました。終了ステータスは%dです。\n", WEXITSTATUS(status));
        }
    }

    return 0;
}

このコードでは、子プロセスが終了した時の状態を親プロセスで取得します。

wait関数の引数にはステータスを格納するための変数を指定します。

WIFEXITEDマクロは子プロセスが正常に終了したかどうかをチェックし、WEXITSTATUSマクロは子プロセスの終了ステータスを取得します。

これらのコードを実行すると、まず子プロセスが実行され、その後で親プロセスが実行されることがわかります。

●wait関数の注意点と対処法

しかし、wait関数には注意すべき点もあります。

それは、子プロセスが終了するまで親プロセスがブロックされるという特性上、子プロセスが終了しない状況では親プロセスも永遠にブロックされてしまうという問題です。

これを避けるためには、親プロセスから子プロセスに対して何らかの終了シグナルを送る、タイムアウトを設けるなどの対策が必要になります。

また、子プロセスのプログラム自体が必ず終了するように設計することも大切です。

●wait関数の詳細なカスタマイズ方法

wait関数はカスタマイズ可能で、具体的にはwaitpid関数を使うことでより柔軟な子プロセスの終了待ちが可能です。

たとえば、特定の子プロセスのみを対象にする、ブロックせずに終了を待つ、といったことが可能になります。

○サンプルコード3:wait関数のカスタマイズ例

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

int main() {
    pid_t pid = fork();
    int status;

    if (pid == 0) {
        printf("これは子プロセスです。\n");
    } else {
        // ブロックせずに子プロセスの終了を待つ
        while (waitpid(pid, &status, WNOHANG) == 0) {
            // 子プロセスがまだ終了していない
            sleep(1);
        }
        printf("これは親プロセスで、子プロセスの終了を待ちました。\n");
    }

    return 0;
}

このコードでは、waitpid関数にWNOHANGオプションを指定することで、子プロセスがまだ終了していない場合に親プロセスをブロックせずにすぐに戻ります。

そのため、親プロセスが他の処理を行いつつ、定期的に子プロセスの終了を確認することができます。

●wait関数の応用例

wait関数は、プロセス制御における重要な要素であり、その活用範囲は広範です。

具体的な応用例として、プロセス管理とマルチスレッドプログラミングの両方を考慮したコードを紹介します。

○サンプルコード4:プロセス管理におけるwait関数の活用

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

int main() {
    pid_t pid = fork();
    int status;

    if (pid == 0) {
        // 子プロセスで重い処理を行う
        for (int i = 0; i < 10; i++) {
            printf("子プロセスの処理中...\n");
            sleep(1);
        }
        printf("子プロセスの処理が完了しました。\n");
    } else {
        // 親プロセスが子プロセスの終了を待つ
        wait(&status);
        printf("これは親プロセスで、子プロセスの終了を待ちました。\n");
    }

    return 0;
}

このコードは子プロセスが何らかの時間がかかる処理を行い、それが終了したら親プロセスがそれを確認するというものです。

重い処理をバックグラウンドで行いつつ、親プロセスはそれが終了するのを待つという形式は非常に一般的です。

○サンプルコード5:マルチスレッドプログラミングにおけるwait関数の応用

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

int main() {
    pid_t pid1 = fork();
    pid_t pid2;
    int status;

    if (pid1 == 0) {
        // 子プロセス1の処理
        printf("これは子プロセス1です。\n");
    } else {
        pid2 = fork();
        if (pid2 == 0) {
            // 子プロセス2の処理
            printf("これは子プロセス2です。\n");
        } else {
            // 親プロセスが子プロセスの終了を待つ
            wait(NULL);
            printf("これは親プロセスで、子プロセス1の終了を待ちました。\n");
            wait(NULL);
            printf("これは親プロセスで、子プロセス2の終了を待ちました。\n");
        }
    }

    return 0;
}

このコードでは、2つの子プロセスが生成され、親プロセスがそれぞれの終了を順に待つものです。

マルチスレッドプログラミングにおいては、複数のスレッドやプロセスが終了を同期するためにwait関数が用いられます。

まとめ

以上、C言語のwait関数について、その基本から応用までを解説しました。

この記事を通じて、wait関数の使い方やその注意点、さらには応用例について理解することができたことでしょう。

プロセス間の同期はプログラミングにおける重要な概念であり、wait関数の理解はそれを深める一助となるはずです。

プログラミングスキルの向上に役立ててください。