2017-04-24 63 views
0

我試圖使用匿名管道作爲子進程讀取的文件的替代品。我遇到的問題是子流程掛起,我想,因爲它不能識別已經到達「文件」(管道)的末尾。popen用/ dev/fd/n匿名管道掛起子進程

下面是我在做什麼一些示例代碼:

#include <stdio.h> 
#include <unistd.h> 
#include <sys/fcntl.h> 

int main() 
    { 
    int pipefd[2]; 
    pipe(pipefd); 
    fcntl(pipefd[0], F_SETFL, O_NONBLOCK); // necessary? 

    char cmd[128]; 
    snprintf(cmd, sizeof(cmd), "cat /dev/fd/%i", pipefd[0]); 
    printf("Command: %s\n", cmd); 

#if 1 
    // This works 
    write(pipefd[1], "line1\n", 6); 
    write(pipefd[1], "line2\n", 6); 
    write(pipefd[1], "line3\n", 6); 
    close(pipefd[1]); 
#endif 

    FILE* fp; 
    if ((fp = popen(cmd, "r")) != NULL) 
    { 
// fcntl(fileno(fp), F_SETFL, O_NONBLOCK); // causes SIGPIPE 

#if 0 
    // This doesn't work 
    write(pipefd[1], "line1\n", 6); 
    write(pipefd[1], "line2\n", 6); 
    write(pipefd[1], "line3\n", 6); 
    close(pipefd[1]); 
#endif 

    char buffer[1024]; 
    while (fgets(buffer, sizeof(buffer), fp) != NULL) 
     printf("%s", buffer); 
    printf("retcode: %i\n", pclose(fp)); 
    } 

    close(pipefd[0]); 

    return 0; 
    } 

上述作品給出的代碼。在其中創建一個管道,並使用管道的讀取端創建一個命令,在這種情況下,使用cat。在工作版本中,我將數據寫入管道的寫入端,然後使用popen啓動子進程,並從子進程讀取stdout直到它結束。

我需要做的是將創建子進程(請參閱#if 0塊)後寫入管道。最終,它將以單獨的線程結束。但是,在popen調用之後切換意味着子進程不會結束(掛起),我看不出原因。

我已經嘗試過讓各種流無阻塞,但是在子流程流上這樣做只會導致SIGPIPE失敗。

有誰知道如何得到這個工作?

謝謝!

+1

在popen之前設置pipefd [1]的FD_CLOEXEC標誌。 –

+0

太棒了!謝謝!!你想做出這個答案,我會標記完成! –

回答

0

器一起VS前後做

write(pipefd[1], "line1\n", 6); 
write(pipefd[1], "line2\n", 6); 
write(pipefd[1], "line3\n", 6); 
close(pipefd[1]); 

之間的區別是:如果pipefd[1]是打開的時候POPEN被調用時,分叉/ execed過程也將它打開。當該進程從pipefd[0]中讀取時,它將永遠不會看到EOF,因爲該管道的寫入結束描述符保持打開狀態。此

一個解決方法是設置關閉-on-exec標誌的

fcntl(pipefd[1], F_SETFD, fcntl(pipefd[1], F_GETFD) | FD_CLOEXEC); 

通話在此之前,文件描述符popen方法。