вторник, 13 декабря 2011 г.

Взаимодействие процессов: pipe()

Есть ещё один вид взаимодействия процессов в unix, каналы.
Рассмотрим на примере как это работает.

 Программа parent создает канал с помощью системного вызова pipe(), далее приводит дескрипторы чтения и записи к символьному типу, создает форков(новый процесс, выполняющий ту же самую программу, у потомков fork() возвращает 0), форки вызывают программы src и dst, передавая им дескрипторы записи и чтения соответственно, джёт завершения форков и завершается сама. Программа src передает сообщение с помощью write(), используя дескриптор для записи в канал, который передан ей как аргумент и завершается. Программа dst получает сообщение с помощью read() и выводит его на экран, используя write(). Листинги программ:
/*Файл parent.c: порождает двух форков, ждет их завершения, закрывает канал и завершается*/
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

#define STR_SIZE    32

int
main(void)
{
    int pf[2];
    int pid1, pid2;
    char spf[2][STR_SIZE];

    /*Создание канала. Чтение идет через pf[0], запись - через pf[1]*/
    if(pipe(pf) == -1){
        fprintf(stderr, "pipe() error\n");
        return 1;
    }

    /*Запись дескрипторов для последующей передачи в качестве параметров программам, осуществляющим запись и чтение*/
    sprintf(spf[0], "%d", pf[0]);
    sprintf(spf[1], "%d", pf[1]);

    /*Первый форк вызывает программу src. В качестве параметра передается дескриптор для записи*/
    if((pid1 = fork()) == 0){
        close(pf[0]);
        execl("./src", "src",
                    spf[1], NULL);
        fprintf(stderr, "exec() [src] error\n");
        return 1;
    }

    /*Второй форк вызывает программу dst. В качестве параметра передается дескриптор для чтения*/
    if((pid2 = fork()) == 0){
        close(pf[1]);
        execl("./dst", "dst",
                    spf[0], NULL);
        fprintf(stderr, "exec() [dst] error\n");
        return 1;
    }

    /*Ждем и завершаемся*/
    waitpid(pid1, NULL, 0);
    close(pf[0]);
    close(pf[1]);
    waitpid(pid2, NULL, 0);
    
    return 0;
}
/*Листинг src.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define PP_MESSAGE    "Hello World\n"
#define WAIT_SECS    5

int
main(int argc, char ** argv)
{
    int i, fd;
    if(argc < 2){
        fprintf(stderr, "src: Too few arguments\n");
        return 1;
    }

    fd = atoi(argv[1]);

    fprintf(stderr, "Wait please");
    for(i = 0; i < WAIT_SECS; i++, sleep (1))
        fprintf(stderr, ".");
    fprintf(stderr, "\n");
    
    if(write (fd, PP_MESSAGE,
            strlen(PP_MESSAGE)) == -1){
        fprintf(stderr, "src: write() error\n");
        return 1;
    }

    close(fd);
    return 0;
}
/*Листинг dst,c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char ** argv)
{
    int fd;
    char ch;
    if(argc < 2){
        fprintf(stderr, "dst: Too few arguments\n");
        return 1;
    }

    fd = atoi(argv[1]);
    while(read(fd, &ch, 1) > 0)
        write(1, &ch, 1);

    close(fd);
    return 0;
}
Вот что получается в результате наших махинаций:
Системный вызов pipe()

Комментариев нет:

Отправить комментарий