fork() - 新規プロセスの作成

標準

標準/拡張機能 C/C++ 依存項目

POSIX.1
XPG4
XPG4.2
Single UNIX Specification、バージョン 3

両方  

形式

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

pid_t fork(void);
注: POSIX.1 では <sys/types.h> 組み込みファイルをインクルードする 必要はありませんが、XPG4 ではこれがオプションのヘッダーとして用意されて います。したがって、移植性のため、インクルードすることをお勧めします。

機能説明

新規プロセスを作成します。新規プロセス (子プロセス) は、fork() を 呼び出したプロセス (親プロセス) を正確に複製 したものですが、以下の点で異なっています。
  • 子プロセスには、アクティブなプロセス・グループ ID のいずれとも一致 しない固有のプロセス ID (PID) がある。
  • 子は、異なる親プロセス ID、つまり、fork() を呼び出した プロセスのプロセス ID を持つ。
  • 子には、親のファイル記述子の独自のコピーがあります。子の各ファイル記述子は、親の対応するファイル記述子と同じ オープン・ファイル記述子を指しています。
  • 子には、親のオープン・ディレクトリー・ストリームの独自の コピーがあります。おのおのの子のオープン・ディレクトリー・ストリームは、親の対応するディレクトリー・ ストリームで位置付けるディレクトリー・ストリームを共用することができる。
  • tms 構造体の、以下のエレメントは、子では 0 に設定されます。
    • tms_utime
    • tms_stime
    • tms_cutime
    • tms_cstime

    これらのエレメントの詳細は、times() - プロセスおよび子プロセス時間の取得を参照してください。

  • 子は、親が以前に設定したどのファイル・ロックも継承しません。
  • 子プロセスには、(引数値 0 の alarm() に対する呼び出しの 結果に似た) アラーム・セットはありません。
  • 子には、保留シグナルはありません。
  • 子プロセスは単一スレッドのみを使用します。そのスレッドは、fork() を呼び出した親のスレッドのコピーです。子プロセスには異なるスレッド ID が付きます。 親プロセスがマルチスレッドであった (pthread_create() を少なくとも 1 回呼び出した) 場合、子プロセスは exec() ファミリーの関数を呼び出す前に、async-signal-safe 関数のみを安全に呼び出すことができます。(この制約は、子が exec() ファミリーの関数を呼び出す前に fork() を呼び出した結果として作成されたプロセスにも適用されます。これは、その子プロセスもまたマルチスレッドと見なされるからです。) 子プロセスは、pthread 属性または pthread 安全保護環境を継承しません。async-signal-safe 関数のリストについては、表 1 を参照してください。

その他はすべての点で、子は親と同じです。子は複製であるため、親にあった fork() 呼び出しと同じ呼び出しが、子にも あります。実行はこの fork() 呼び出しから開始され、この呼び出しは値 0 を 戻します。子はその後、通常の実行を続行します。

子アドレス・スペースは、親アドレス・スペースの以下のアドレス・スペース属性を継承します。
  • 領域サイズ
  • 時間制限

親プロセスがマルチスレッドである場合、fork() が発生したときにアプリケーション・データの整合状態を保つことは、アプリケーションが行う必要があります。例えば、アプリケーション・データの更新をシリアライズするために使用される mutex は、fork() の前にロックし、その後でアンロックする必要が生じることがあります。

fork() の詳細については、「z/OS UNIX System Services プログラミング: アセンブラー呼び出し可能サービス 解説書) を参照してください。

MVS™ メモリー・ファイルを z/OS®UNIX プログラムから使用できます。しかし、そのプログラムから fork() 関数を使用すると、子プロセスの ハイパースペース・メモリー・ファイルからアクセスが削除されます。そのプログラムから exec 関数を使用すると、プロセス・アドレス・スペースがクリアされたときにメモリー・ファイルはクリアされます。

マルチスレッド環境で fork() の結果として得られる子プロセスは、async-signal-safe 関数のみを呼び出すことができます。

async-signal-safe 関数は、シグナル・キャッチング関数から無制限に呼び出すことができる関数として定義されます。 サポートされる async-signal-safe 関数すべてのリストを、表 1 に示します。

表 1. async-signal-safe ライブラリー関数
abort() fpathconf() raise() sigpending()
accept() fstat() read() sigprocmask()
access() fsync() readlink() sigqueue()
aio_error() ftruncate() recv() sigset()
aio_return() getegid() recvfrom() sigsuspend()
aio_suspend() geteuid() recvmsg() socket()
alarm() getgid() rename() socketpair()
bind() getgroups() rmdir() stat()
cfgetispeed() getpeername() select() symlink()
cfgetospeed() getpgrp() send() sysconf()
cfsetispeed() getpid() sendmsg() tcdrain()
cfsetospeed() getppid() sendto() tcflow()
chdir() getsockname() setgid() tcflush()
chmod() getsockopt() setpgid() tcgetattr()
chown() getuid() setsid() tcgetpgrp()
close() kill() setsockopt() tcsendbreak()
connect() link() setuid() tcsetattr()
creat() listen() shutdown() tcsetpgrp()
dup() lseek() sigaction() time()
dup2() lstat() sigaddset() times()
execle() mkdir() sigdelset() umask()
execve() mkfifo() sigemptyset() uname()
_Exit() open() sigfillset() unlink()
_exit() pathconf() sigismember() utime()
fchmod() pause() sleep() wait()
fchown() pipe() signal() waitpid()
fcntl() poll() sigpause() write()
fork()      

相互運用性の制約事項: POSIX リソースでは、fork() は記述どおりに動作します。しかし、通常は親に存在する MVS リソースは、子には存在しません。これは、MVS データ・セットのオープン・ストリームや STIMERS のようなアセンブラー・アクセスの MVS 機能に該当します。さらに、MVS 割り振り (JCL、SVC99、または ALLOCATE による) は、子プロセスには受け渡されません。

z/OSUNIX サービスの特殊な動作:
  1. 無許可ライブラリーから MVS XCTL サービスによる、以前ロードされた MVS 無許可プログラムの再利用へ適用する同じ状況下で、同一アドレス・スペースで以前にロードされた HFS プログラムのコピーは 再利用されます。ただし、以下のような例外があります。
    • 呼び出しプロセスが Ptrace デバッグ・モードの場合、以前にロードされたコピーは再使用されません。
    • 呼び出しプロセスが Ptrace デバッグ・モードではない が、HFS プログラムの中で以前にロードした唯一の 使用可能コピーが呼び出し元で変更可能なストレージにある場合、以前のコピーは再利用されません。
  2. 指定のファイル名が外部リンクまたは スティッキー・ビット・ファイルを表す場合、プログラムは 呼び出し元の MVS ロード・ライブラリーの検索順序で ロードされます。外部リンクの場合、外部名は、名前が 8 文字以下の場合にのみ使用されます。その他の場合は、呼び出し元は loadhfs サービスからエラーを受け取ります。スティッキー・ビット・プログラムの場合は、ファイル名は 8 文字以下の場合にのみ使用されます。それ以外の場合、プログラムは HFS からロードされます。
  3. 呼び出しタスクが WLM エンクレーブにある場合、新規プロセス・イメージ内の結果のタスクは、同一 WLM エンクレーブへ結合されます。これにより、WLM はシステムのアカウンティングおよび管理の目的で、新旧のプロセス・イメージを 1 つの「作業単位」エンティティーとして管理できます。

戻り値

fork() は、正常終了時には子プロセスへ 0 を戻し、新規に作成した子 のプロセス ID を親プロセスへ戻します。

正常終了しなかった場合、fork() は、子プロセスの作成に失敗し、親へ -1 を戻して、errno を次のいずれかの値に設定します。
エラー・コード
説明
EAGAIN
別プロセスを作成するのに必要なリソースが足りないか、または プロセスが既に実行できるプロセスの最大数に達しました。
ELEMSGERR
Language Environment® のメッセージ・ファイルが使用できません。
ELEMULTITHREAD
アプリケーションがマルチスレッド環境での fork() をサポートしない言語を含んでいるか、Language Environment の事前初期設定 (CEEPIPI) 環境での実行中にマルチスレッドの fork() が試行されています。
ELENOFORK
アプリケーションに、fork() をサポートしない言語が 含まれています。
ENOMEM
プロセスには、現在使用可能なスペース以上のスペースが必要です。

CELEBF27
⁄* CELEBF27

   This example creates a new child process.

 *⁄
#define _POSIX_SOURCE
#include <sys⁄types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys⁄wait.h>

main() {
  pid_t pid;
  int status;

  if ((pid = fork()) < 0)
    perror("fork() error");
  else if (pid == 0) {
    puts("This is the child.");
    printf("Child's pid is %d and my parent's is %d¥n",
           (int) getpid(), (int) getppid());
    exit(42);
  }
  else {
    puts("This is the parent.");
    printf("Parent's pid is %d and my child's is %d¥n",
           (int) getpid(), (int) pid);
    puts("I'm waiting for my child to complete.");
    if (wait(&status) == -1)
      perror("wait() error");
    else if (WIFEXITED(status))
           printf("The child exited with status of %d¥n",
                  WEXITSTATUS(status));
         else
           puts("The child did not exit successfully");
  }
}
出力:
This is the parent.
This is the child.
Child's pid is 1114120 and my parent's is 2293766
Parent's pid is 2293766 and my child's is 1114120
I'm waiting for my child to complete.
The child exited with status of 42

関連情報