处理大量管道数据时需要建议

时间:2019-05-22 20:44:18

标签: c linux pipe

我正在通过管道系统调用来练习C代码,它可以很好地处理少量数据。但是当数据超出管道容量时,就会发生死锁。

我的测试系统是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 个答案:

答案 0 :(得分:2)

第一个进程通过管道catcat管道回到第一个进程。因此,为了使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]是否准备好写,而{{1 }}进行读取,然后进行相应的写入/读取,并处理部分读取和写入。

答案 1 :(得分:0)

根据您的建议,至少我有2种方法可以解决此问题 1.通过'fcntl'或'select / poll / epoll'设置'NON-BLOCK'模式

  1. 对stdin管道使用诸如“ pthread”之类的并发性 一段代码。
        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);

谢谢!