名前なしパイプ(2)

パイプの仕組みについては名前なしパイプ(1)
ここでは, パイプを用いて足し算を行うプログラムやります.

                        #include<stdio.h>
#include<stdlib.h> // exit
#include<string.h> // strlen
#include<unistd.h> // fork

void error_message(const char *name);

int main(int argc, char **argv)
{
    pid_t pid;
    int na, nb, nc;
    int pa[2], pb[2];
    char buff[32], result[32];

    if(pipe(pa) == EOF || pipe(pb) == EOF)
        error_message("pipe");

    if((pid = fork()) == EOF)
        error_message("fork");

    else if(pid == 0) { //child process
        close(pa[1]);
        close(pb[0]);
        if(read(pa[0], buff, 32) == EOF)
            error_message("read");
        na = atoi(buff);

        if(read(pa[0], buff, 32) == EOF)
            error_message("read");
        nb = atoi(buff);

        nc = na + nb;

        sprintf(result, "%d", nc);

        if(write(pb[1], result, strlen(result) + 1) == EOF)
            error_message("write");

        printf("Child Process(PID:%d) Send Answer...\n", getpid());

        close(pa[0]);
        close(pb[1]);
    }

    else {
        close(pa[0]);
        close(pb[1]);

        printf("Parent Process(PID:%d)\n", getpid());
        printf("NumA:");
        fgets(buff, 32, stdin);
        if(write(pa[1], buff, strlen(buff) + 1) == EOF)
            error_message("write");

        printf("NumB:");
        fgets(buff, 32, stdin);
        if(write(pa[1], buff, strlen(buff) + 1) == EOF)
            error_message("write");

        if(read(pb[0], result, 32) == EOF)
            error_message("read");

        printf("Answer = %s\n", result);

        close(pa[1]);
        close(pb[0]);
    }

    return 0;
}

void error_message(const char *name) {
    perror(name);
    exit(EXIT_FAILURE);
}
                        

$ ./sc
Parent Process(PID:25778)
NumA:12
NumB:34
Child Process(PID:25779) Send Answer...
Answer = 46


プログラムの説明

70行程度のプログラムですが, やっていることは単純で, 親プロセスが子プロセスにパイプを使い数値を送信して, 子プロセスで受信後に計算し親プロセスに送信, 親プロセスで受信, 表示しているだけです.
上から順に説明をしていきます.

int pa[2], pb[2];
if(pipe(pa) == EOF || pipe(pb) == EOF)
    error_message("pipe");
この部分はパイプを作成しているだけです.
error_message()はエラー処理をまとめているだけで, 度々でてきます.
pid_t pid;
if((pid = fork()) == EOF)
    error_message("fork");
子プロセスの作成. pidが"0"ならば子プロセス, pidが"0"以上なら親プロセス.
else if(pid == 0) { //child process
    close(pa[1]);
    close(pb[0]);
    if(read(pa[0], buff, 32) == EOF)
        error_message("read");
    na = atoi(buff);

    if(read(pa[0], buff, 32) == EOF)
        error_message("read");
    nb = atoi(buff);

    nc = na + nb;

    sprintf(result, "%d", nc);

    if(write(pb[1], result, strlen(result) + 1) == EOF)
        error_message("write");

    printf("Child Process(PID:%d) Send Answer...\n", getpid());

    close(pa[0]);
    close(pb[1]);
}

else { //parent process
    close(pa[0]);
    close(pb[1]);

    printf("Parent Process(PID:%d)\n", getpid());
    printf("NumA:");
    fgets(buff, 32, stdin);
    if(write(pa[1], buff, strlen(buff) + 1) == EOF)
        error_message("write");

    printf("NumB:");
    fgets(buff, 32, stdin);
    if(write(pa[1], buff, strlen(buff) + 1) == EOF)
        error_message("write");

    if(read(pb[0], result, 32) == EOF)
        error_message("read");

    printf("Answer = %s\n", result);

    close(pa[1]);
    close(pb[0]);
}
必要なパイプだけを開き, 親プロセスで数値を送信し, 子プロセスで受け取り答えを親プロセスに送信しています.

"wait"関数を用いると子プロセスが終了するまで親プロセスは実行されないので, "wait"を使わずプロセスのやりとりを交互にさせることで送受信を行っています.