プロセスグループ

 プログラム中で新しいプロセス(子プロセス)を生成して処理を行う際、メインプロセスから子プロセスを終了させるのは kill() で簡単にできます。

 しかし、子プロセスが更に孫プロセスを生成した場合、孫プロセスをメインプロセスから kill() で終了させることはできません。孫プロセスの PID(プロセス ID)がわからないためです。

 スレッドと異なり、プロセスのメモリ空間はそれぞれ独立しているため、直接データのやり取りはできません。

 次のプログラムを動かしてみます。ファイル名を a.c とします。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

void start_grandchild() {
    int pid;

    pid = fork();
    if( pid == -1 ) {
        printf("fork faild.\n");
    }
    if( pid == 0 ) {
        while( 1 ) {
            printf("Grandchild running(pid:%d).\n", getpid());
            sleep(3);
        }
    }
}

pid_t start_child() {
    int pid;

    pid = fork();
    if( pid == -1 ) {
        printf("fork faild.\n");
        return 0;
    }
    if( pid == 0 ) {
        printf("start grandchild.\n");
        start_grandchild();
        while( 1 ) {
            printf("Child running(pid:%d).\n", getpid());
            sleep(2);
        }
    }

    return pid;
}

int main(int argc, char *argv) {
    pid_t pid;

    printf("start child.\n");
    pid = start_child();

    sleep(10);

    printf("Stop child process.\n");
    kill(pid, SIGTERM);
    sleep(10);

    return 0;
}

 コンパイルして実行してみます。

$ gcc a.c
$ ./a.out 
start child.
start grandchild.
Child running(pid:2615).
Grandchild running(pid:2616).
Child running(pid:2615).
Grandchild running(pid:2616).
Child running(pid:2615).
Child running(pid:2615).
Grandchild running(pid:2616).
Child running(pid:2615).
Grandchild running(pid:2616).
Stop child process.
Grandchild running(pid:2616).
Grandchild running(pid:2616).
Grandchild running(pid:2616).
$ Grandchild running(pid:2616).
Grandchild running(pid:2616).
Grandchild running(pid:2616).
Grandchild running(pid:2616).
kill 2616
$

 最後は kill コマンドで孫プロセスを終了させています。

 このような場合、子プロセスで新たに PGID(プロセスグループ ID)を設定することでそのプロセスグループに対して signal を送ることができます。

 setpgid() で子プロセスのプロセスグループ ID を変更し、kill() の代わりに killpg() を使って終了させます。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

void start_grandchild() {
    int pid;

    pid = fork();
    if( pid == -1 ) {
        printf("fork faild\n");
    }
    if( pid == 0 ) {
        while( 1 ) {
            printf("Grandchild running(pid:%d).\n", getpid());
            sleep(3);
        }
    }
}

pid_t start_child() {
    int pid;

    pid = fork();
    if( pid == -1 ) {
        printf("fork faild\n");
        return 0;
    }
    if( pid == 0 ) {
        pid = getpid();
        printf("set pgid %d.\n", pid);
        setpgid(pid, pid);
        printf("start grandchild.\n");
        start_grandchild();
        while( 1 ) {
            printf("Child running(pid:%d).\n", getpid());
            sleep(2);
        }
    }

    return pid;
}

int main(int argc, char *argv) {
    pid_t pid;

    printf("start child.\n");
    pid = start_child();

    sleep(10);

    printf("Stop child process.\n");
    killpg(pid, SIGTERM);
    sleep(10);

    return 0;
}

 実行してみます。

$ gcc a.c
$ ./a.out
start child.
set pgid 2696.
start grandchild.
Child running(pid:2696).
Grandchild running(pid:2697).
Child running(pid:2696).
Grandchild running(pid:2697).
Child running(pid:2696).
Child running(pid:2696).
Grandchild running(pid:2697).
Child running(pid:2696).
Grandchild running(pid:2697).
Stop child process.
$

 子プロセスも孫プロセスも終了します。子プロセスでシグナルハンドラを使い、孫プロセスを終了させる方法もあると思いますが、プロセスグループを使ったほうがスッキリすると思います。

プログラミング

Posted by sirius