日々精進

aikoと旅行とプログラミング

新たなプロセスを生成するfork関数&wait関数メモ

今回はC言語の話。新たなプロセスを生成するfork関数と、併用することが多いwait関数についてのメモ。
【2015/12/01】exit関数とsleep関数を追記

書式

fork関数
#include <unistd.h>

pid_t fork(void);  
wait関数
#include <sys/wait.h>

pid_t wait(int *status);

概要

fork関数

呼び出し元のプロセスをコピーして新たなプロセスを生成する。コピーして新たなプロセスを生成するため、変数やポインタなどもそのまま使用することができる。呼び出し元のプロセスを親プロセス、生成されたプロセスを子プロセスと呼ぶことにする。

wait関数

プロセスの状態変化を待つ。親プロセスが子プロセスの状態変化を待つ。状態変化とは、子プロセスの終了やシグナルによるプロセスの停止・再開などを指す。またwait関数をりよすることで、子プロセスの利用していたリソースを開放することができる。子プロセスの状態変化がすでに起こっていた場合、wait関数はすぐに復帰する。
引数のstatusには子プロセスの終了状態が格納される。以下のマクロを利用することで、容易に情報にアクセスすることができる。

名前 機能
WIFEXITED(status) 子プロセスが正常に終了した場合に真を返す。 「正常に」とは、 exit(3)かexit(2)が呼び出された場合、もしくは main() から復帰した場合である。
WEXITSTATUS(status) 子プロセスの終了ステータスを返。 このマクロを使用するのは WIFEXITED がtrueとなった時。
WIFSIGNALED(status) 子プロセスがシグナルにより終了した場合に真を返す。
WTERMSIG(status) 子プロセス終了の原因となったシグナルの番号を返す。 このマクロを使用するのは WIFSIGNALED が真を返した場合だけにすべきである。

返り値

fork関数

成功した場合には、親プロセスには子プロセスのIDが返り子プロセスには0が返る。失敗した場合には親プロセスに-1が返る。成功した場合の返り値によって、親プロセスと子プロセスにさせる処理を分ける処理が一般的である。

wait関数

成功すると終了した子プロセスのIDが返る。エラーの場合は-1が返る。

実装例

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

int main(int argc, char *argv[]){
  int pid;
  int code;
  int status;
  pid_t result;

  pid = fork();
  
  // fork失敗
  if(pid == -1){
    fprintf(stderr, "Error\n\n");
  }
  
  // 子プロセスの処理
  if(pid == 0){
    printf("Child Process\n");
    sleep(1);
  }else{
    printf("Parent Process\n");
    
    result = wait(&status);
    
    if(result < 0){
      fprintf(stderr, "Wait Error.\n\n");
      exit(-1);
    }

    // 終了ステータスのチェック
    if(WIFEXITED(status)){
      printf("子プロセス終了");
      code = WEXITSTATUS(status);
      printf("コード : %d\n", code);
    }else{
      printf("wait失敗");
      printf("終了コード : %d\n", status);
    }

    // シグナルによる終了
    if (WIFSIGNALED(status)) {
      printf("シグナル番号:%dによる終了。\n",WTERMSIG(status));
    }
    
    printf("親プロセス終了\n");
  }

  return 0;
}

実行結果

Parent Process
Child Process
子プロセス終了コード : 0
親プロセス終了

プロセスに関するその他の関数

exit関数
#include <stdlib.h>

void exit(int status);

プロセスを正常に終了させ、親プロセスに対してstatus & 0377という値を返す。wait関数のstatusはこれになる。

sleep関数
#include <unistd.h>

unsigned int sleep(unsigned int seconds);

呼び出したスレッド・タスク・プロセスをseconds秒停止する。sleep関数はSIGALRMを用いて実装されている。そのためalarm関数を用いてsleepの機能を実装することもできる。