2014-11-14 20 views
1

我正在使用这两个程序的this答案。这个答案使用命名管道而不是管道,我是否正确?在管道中传输的数据是垃圾

我写了main.c,它实际上是我的实际项目的代码,最小化到这个特定的问题(这就是为什么我有一个for循环为例)。

#include <unistd.h> 
#include <sys/wait.h> 
#include <stddef.h> 
#include <limits.h> 
#include <stdio.h> 


int main(void) { 
    pid_t pid; 

    int i; 
    for(i = 0; i < 2; ++i) { 
    pid = fork(); 
    if (pid == -1) { 
     // error, failed to fork() 
     perror("failed to fork()"); 
     return 1; 
    } else if (pid == 0) { 
     // child code 
     if(i < 1) { 
     // the writer.c 
     char* arg_list[] = { "w", NULL }; 
     execv("w", arg_list); 
     printf("exec FAILED\n"); 
     } else { 
     // the reader.c 
     char* arg_list[] = { "r", NULL }; 
     execv("r", arg_list); 
     printf("exec FAILED\n"); 
     } 
    } 
    } 

    // parent code 
    int status; 
    // wait for all children to terminate 
    while ((pid = wait(&status)) > 0) { 
    if (status == 1) { 
     printf("The child process terminated with an error!\n"); 
     return -1; 
    } 
    } 
    printf("All children are done\n"); 

    return 0; 
} 

的问题是,有时,读取器接收垃圾(或最有可能没有),并挂断了电话。

输出示例:

Received: Hi 
All children are done 
[email protected]:~/test$ ./m 
Received: Hi 
All children are done 
[email protected]:~/test$ ./m 
Received:  <----------------- This is garbage, that is not reproducible 
^C 

所以,我缺少什么?

不需要在下面阅读。


我的猜测。(不检查,所以如果我是正确的,我仍然需要澄清):

读写器之前运行,这就是为什么它有垃圾,但为什么它挂起?

我需要写一个包装函数read_all()(一个用于写入的情况下呢?),收集所有的管道吐数据,但为什么,如果我取代“喜”与“H “,我有同样的行为?


编辑:

如果我的第一个猜测的话,我把一个循环的阅读,但它会在读者先启动的情况下永远执行。

在我看到垃圾的情况下,与strace -f运行后,我得到这个:

... 
[pid 3326] read(-1, 0xbfddd80c, 1024) = -1 EBADF (Bad file descriptor)^C 
Process 3324 resumed 
Process 3325 detached 
Process 3326 detached 
+0

*您应该*在read()方法周围使用读循环来确保读取所有字节。同样,你应该在write()方法周围使用写循环来确保写入所有字节。但是,我认为你没有做这些事情对你所观察到的行为负责。在'strace -f'下运行你的程序可能会提供更多的洞察。 – 2014-11-14 21:05:54

+0

请注意,如果您不需要或不想管理低级'read()'和'write()'调用,您可以'打开()'您的FIFO并使用流I/O。 – 2014-11-14 21:08:10

+0

那么在这种情况下,我应该怎么知道我需要阅读多少个角色?我并不清楚这一开始。我的意思是我真的不知道这个循环如何看起来像@JohnBollinger。 – gsamaras 2014-11-14 21:08:41

回答

1

你的循环(或缺乏)有什么关系呢。当您的阅读器打开时(open())在编写器创建管道之前读取的管道,则您的阅读器等待的文件描述符无效(-1)。所以,即使作家稍后写了一些东西,读者也只是在等待一个无效的fd(-1),并且永远不会读任何东西。普通的,你可以用下面的方法解决它:

while((fd = open(myfifo, O_RDONLY)) == -1); 

在阅读器中,以便它等到管道可用。我实际上想知道是否可以有比这更好的方法。我可以想到的另一种方式是在access()之上循环,但它与此没有大的差异......

+0

我也有一个关于这行'char * myfifo =“/ tmp/myfifo”;''的问题。比方说,我会有两位作家和两位读者,我希望一位读者能够从两位作家中读取,并且同样能够读取其他读者的行为。我应该改变这条线吗?我的意思是这个'tmp/myfifo'被视为共享地址空间?我还没有接受你的答案,看看是否有人进来更有效率的东西。 :) – gsamaras 2014-11-14 22:43:06

+0

命名管道在概念上类似于正常文件,其中一个进程和写入以及另一个读取。与普通文件不同,写入管道的数据只能读取一次。所以多个读者不能“共享”管道。多个写入者可以写入相同的管道,但数据可能会交错或可能损坏。管道不是为多个进程的读/写而设计的。您最好使用其他[IPC机制](http://en.wikipedia.org/wiki/Inter-process_communication#Approaches)。 – 2014-11-14 23:10:56

+0

我被指示使用命名管道。所以我应该创建更多的管道。我还有多少东西需要考虑。 – gsamaras 2014-11-14 23:22:43