fork-exec において
複数の子プロセスを生み出して、常に一定のプロセスを起動させるにはどのようにすれば良いだろうか。
いまいちイディオム的なのがよくわからなかったので、必死こいて作ってみた。
子プロセスが exec するプログラム(sleep というファイル名にコンパイル)
1 // $Id:$ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 6 // 引数秒 sleep するだけ。 7 int main(int argc, char* argv[]) { 8 if(argc == 1) { 9 puts("exit"); 10 exit(1); 11 } 12 13 printf("sleep(%s)...\n", argv[1]); 14 sleep(atoi(argv[1])); 15 puts("sleep ... end"); 16 return 0; 17 }
こいつを exec するメインプログラム
1 // $Id:$ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/wait.h> 6 7 #define MAX_PROC 5 8 9 int main(void) { 10 pid_t pid[MAX_PROC] = {0}; 11 int proc_count = 0; 12 int status = 0; 13 14 while(1){ 15 puts("while"); 16 pid[proc_count] = fork(); 17 if (pid[proc_count] == -1) { 18 puts("error"); 19 exit(1); 20 } 21 if (pid[proc_count] == 0) { 22 char string[256] = {'\0'}; 23 sprintf(string, "%d", getpid() & 0x09); 24 puts("child"); 25 execl("./sleep", "./sleep", string, NULL); 26 } 27 // 子プロセスの起動を見届けたらカウンタ追加 28 proc_count++; 29 if (proc_count == MAX_PROC) { 30 int i = 0; 31 int tmp[MAX_PROC] = {0}; 32 pid_t exist_pid = 0; 33 printf("parent = %d\n", getpid()); 34 /* 子プロセスの終了を待機する */ 35 exist_pid = wait(&status); 36 37 /* pid配列から終了したプロセスの pid を抜き取る 38 * しかしいくらなんでもこれはダサイ。単方向リストとか作れば良いのか? 39 */ 40 for(i = 0; i < MAX_PROC; i++) { 41 if(pid[i] != exist_pid) { 42 tmp[i] = pid[i]; 43 } 44 } 45 for(i = 0; i < MAX_PROC; i++) { 46 pid[i] = tmp[i]; 47 } 48 /* ダサイゾーン終了 */ 49 50 if (WIFEXITED(status)) { 51 printf("pid = %d, exited, status=%d\n",exist_pid, WEXITSTATUS(status)); 52 proc_count--; 53 } 54 } 55 } 56 return 0; 57 } 58
簡単に解説しておくと、
- 子プロセスを fork で生成する。ただし、上限は5つ。
- プロセス生成上限値まで来たら親プロセスは子プロセスの終了(生成順ではなく、終了順)を待つ。
- 子プロセスが消えたら子プロセス管理用の配列から終了した子プロセスIDを削除して、また子プロセスを生成する
これで複数プロセスの fork-exec の完成・・・なのだろうか。動き的には大丈夫そうだけど、無駄はありそうな気がする。
というか、今の作りだと pid[] の配列が全く使われていない(多分、単一の変数で大丈夫な気がしてきた)にも関わらず無駄に配列のリフレッシュを行っていて死ぬほどださい。
っていうのを、2時間くらい掛けてつくった/(^o^)\
C言語は
こういうシンプルなものを作るだけでもやたらとがんばる必要があるので、なんかこう、「やってやったぜ!」という気になれる素晴らしい言語ですね。