「複数の子プロセスをforkする」の版間の差分

提供: C言語入門
移動: 案内検索
(ページの作成:「fork()を何度も呼び出すことで、複数の子プロセスを作成できます。一定数の複数の子プロセスをfork()し、waitpid()で回収しつつ...」)
(相違点なし)

2014年5月17日 (土) 00:08時点における版

fork()を何度も呼び出すことで、複数の子プロセスを作成できます。一定数の複数の子プロセスをfork()し、waitpid()で回収しつつ、一定数の子プロセスを維持する例です。

概要

ここで紹介するのは、複数の子プロセスを持ち、子プロセスに処理を任せるようなマルチプロセスのデーモンを作成するときに参考にするための簡単な例です。 Apache (preforkモデル)のようなマルチプロセスのデーモンは、子プロセスを生成し、子プロセスに処理を任せます。そのようなアプリケーションは、子プロセスが終了したら、新たに作成します。

multi_fork.c の例

このプログラムは、以下のポリシーで作成されています。

  • 子プロセスはランダムの秒数だけ実行され、終了します。
  • 同時に持つ子プロセスの数の上限を持ちます。
  • 子プロセスの数の上限までfork()したら、子供が終了するのを待ちます。
  • fork()する最大数を設定しています。最大数に達したら、子プロセスのすべての終了を待ち、プログラムも終了します。

ソースコード multi_fork.c

/*
 * multi_fork.c
 * Copyright (C) 2014 kaoru <kaoru@bsd>
 */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
 
#include <sys/types.h>	// fork
#include <unistd.h>	// fork
#include <sys/wait.h>	// wait
 
#include <err.h>
#include <errno.h>
 
pid_t
Fork()
{
	pid_t pid = fork();
	if (-1 == pid) {
		err(EXIT_FAILURE, "can not fork");
	}
	return pid;
}
 
pid_t
Waitpid(pid_t wpid, int *status, int options)
{
	for(;;){
		pid_t pid = waitpid(wpid, status, options);
		if (-1 == pid){
			if (EINTR == errno){
				(void) printf ("EINTR\n");
				continue;
			}
			if (ECHILD == errno){
				(void) printf("no child\n");
			}
			else {
				err(EXIT_FAILURE, "can not wait");
			}
		}
		return (pid);
	}
}
 
void
wait_children (ssize_t *child) {
	int status;
	int options = WEXITED;
 
	bool is_first = true;
	for(;*child > 0;) {
		pid_t pid = Waitpid(-1, &status, options);
		if (-1 == pid) {
			return;
		} else if (0 == pid) {
			return;
		}
		(*child)--;
		if (is_first) {
			is_first = false;
			options = WNOHANG;
		}
	}
}
 
void
doit()
{
	srandom( getpid() );
	unsigned int sleep_sec = random() % 3;
	sleep (sleep_sec);
}
 
int
main(int argc, char *argv[])
{
	const ssize_t child_max = 30;	// 同時最大子プロセス数
	const ssize_t fork_max = 70;	// forkの最大数
	ssize_t child = 0;		// 現在の子プロセスの数
	ssize_t fork_count = 0;		// 現在のfork()の回数
 
	ssize_t i = 0;
	for ( ; fork_count <= fork_max; ) {
		(void) printf ("fork_count=%lu, child=%lu\n", fork_count, child);
		for (; child < child_max; child++, fork_count++) {
			pid_t pid = Fork ();
			if (0 == pid) {
				doit();
				_exit(EXIT_SUCCESS);
			}
		}
		wait_children(&child);
	}
	while (child > 0) {
		wait_children(&child);
	}
 
	exit (EXIT_SUCCESS);
}

コンパイル

cc  --out multi_fork.c -o multi_fork

実行例

% ./multi_fork
fork_count=0, child=0
fork_count=30, child=18
fork_count=42, child=27
fork_count=45, child=29
fork_count=46, child=29
fork_count=47, child=29
fork_count=48, child=29
fork_count=49, child=29
fork_count=50, child=29
fork_count=51, child=10

関連項目