Нужно предложение при обработке огромных данных канала - PullRequest
0 голосов
/ 22 мая 2019

Я практикую C-код с системным вызовом pipe, он хорошо работает с небольшими порциями данных. но когда данные выходят за пределы пропускной способности канала, возникает мертвая блокировка.

Моя тестовая система - Debian Sid, но я считаю, что она имеет общий язык с другими дистрибутивами Linux. Этот фрагмент кода работает хорошо, в то время как входной файл '/tmp/a.out' достаточно мал, чтобы поместиться в канале, но заблокирован, так как размер файла составляет до 1M.

#include <sys/errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>

#define CHUNK 2048
int main() {
    int fd=open("/tmp/a.out",O_RDONLY);
    int pin[2];
    int pout[2];

    int nread;
    char buff[CHUNK];

    pipe(pin);
    pipe(pout);
    int rc;
    pid_t pid=fork();
    if (pid == 0) {
        close(pin[1]);
        dup2(pin[0],STDIN_FILENO);
        close(pout[0]);
        dup2(pout[1],STDOUT_FILENO);

        execlp("cat","cat",(char *)0);
    } else if (pid > 0) {
        close(pin[0]);
        close(pout[1]);

/* I think dead lock occurs here, but i can't figure out a way to avoid it */ 
        while ( (nread=read(fd,buff,CHUNK)) > 0) write(pin[1],buff,nread);
        close(pin[1]);
        while ( (nread=read(pout[0],buff,CHUNK)) >0) write(STDOUT_FILENO,buff,nread);



        waitpid(pid,&rc,0);
        exit(rc);

    } else {
        perror("fork");
        exit(errno);
    }
}

Есть предложения? Я знаю, что у класса подпроцесса Python есть что-то вроде subprocess.communicate (), чтобы избежать такой блокировки, но я не знаю, как с этим справиться в C.

Большое спасибо.

Ответы [ 2 ]

2 голосов
/ 22 мая 2019

Первые технологические трубы в cat и cat возвращаются в первый процесс.Следовательно, чтобы cat не блокировал трубопровод, первый процесс также должен дренировать эту трубу.Например:

fcntl(pout[0], F_SETFL, fcntl(pout[0], F_GETFL) | O_NONBLOCK);
while((nread=read(fd, buff, CHUNK)) > 0) {
    write(pin[1], buff, nread); // TODO: check errors and partial writes here.
    while((nread=read(pout[0],buff,CHUNK)) > 0) // pout[0] must be set into non-blocking mode.
        write(STDOUT_FILENO, buff, nread);
}

Более надежный способ - установить pin[1] и pout[0] в неблокирующий режим, используйте select, чтобы определить, готов ли pin[1] к записи, и pout[0]для чтения, а затем выполнять запись / чтение соответственно и обрабатывать частичные операции чтения и записи.

0 голосов
/ 23 мая 2019

По вашим предложениям, по крайней мере, у меня есть 2 способа решения этой проблемы 1. Установка режима «NON-BLOCK» с помощью «fcntl» или «select / poll / epoll»

Используйте параллелизм, такой как 'pthread' для присоединенного фрагмента кода stdin pipe.
        struct data {
             int from_fd;
             int to_fd;
        };

и код для труб должен выглядеть так:


        pthread_t t;
        struct data d;
        d.from_fd=fd;
        d.to_fd=pin[1];
        pthread_create(&t,NULL,&fd_to_pipe,(void*) &d);

        while ( (nread=read(pout[0],buff,CHUNK)) >0) write(STDOUT_FILENO,buff,nread);

        waitpid(pid,&rc,0);
        pthread_join(t,NULL);

Спасибо!

...