【发布时间】:2015-11-08 06:02:20
【问题描述】:
我在使用 unix 管道时遇到了一个奇怪的错误。我写了一个简短的程序来展示这个问题。
代码如下:
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char*args[]){
int fd[2];
pipe(fd);
int pid = fork();
if(pid<0){
perror("fork()");
exit(1);
}else if(pid == 0){
close(fd[0]);
const char* msg = "I'm here\n";
size_t len = strlen(msg) + 1; // +1 for null char
write(fd[1], msg, len);
while(1){/*does other work*/}
}else{
close(fd[1]);
}
pid = fork();
if(pid<0){
perror("fork()");
exit(1);
}else if(pid == 0){
close(fd[0]);
const char* msg = "I'm here\n";
size_t len = strlen(msg) + 1; // +1 for null char
write(fd[1], msg, len);
while(1){/*does other work*/}
}else{
close(fd[1]);
}
//close(fd[1]);
sleep(5);
const char* msg = "I'm here\n";
size_t len = strlen(msg) + 1; // +1 for null char
char str[len];
fcntl(fd[0],F_SETFL, O_NONBLOCK);
if(read(fd[0], str, len)<=0){
printf("Nothing from child\n");
}
/*does other work*/
fcntl(fd[0],F_SETFL, O_NONBLOCK);
if(read(fd[0], str, len)<=0){
printf("Nothing from child\n");
}
printf("finished read\n");
/*does other work*/
wait(NULL);
return 0;
}
父进程派生出两个子进程并创建一个管道。两个子进程写入管道,父进程从管道读取。
父进程应该恢复子进程写入的所有信息。
但是,当我运行上述程序时,父级打印出来
Nothing from child
finished read
为什么?
有趣的是,如果我这样写一个 close(fd[1]):
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char*args[]){
int fd[2];
pipe(fd);
int pid = fork();
if(pid<0){
perror("fork()");
exit(1);
}else if(pid == 0){
close(fd[0]);
const char* msg = "I'm here\n";
size_t len = strlen(msg) + 1; // +1 for null char
write(fd[1], msg, len);
while(1){/*does other work*/}
}else{
}
pid = fork();
if(pid<0){
perror("fork()");
exit(1);
}else if(pid == 0){
close(fd[0]);
const char* msg = "I'm here\n";
size_t len = strlen(msg) + 1; // +1 for null char
write(fd[1], msg, len);
while(1){/*does other work*/}
}else{
}
close(fd[1]);//HERE IS THE DIFFERENCE
sleep(5);
const char* msg = "I'm here\n";
size_t len = strlen(msg) + 1; // +1 for null char
char str[len];
fcntl(fd[0],F_SETFL, O_NONBLOCK);
if(read(fd[0], str, len)<=0){
printf("Nothing from child\n");
}
/*does other work*/
fcntl(fd[0],F_SETFL, O_NONBLOCK);
if(read(fd[0], str, len)<=0){
printf("Nothing from child\n");
}
printf("finished read\n");
/*does other work*/
wait(NULL);
return 0;
}
它有效,如果我根本没有 close(fd[1]) 也有效。我很迷茫,为什么 close() 的位置会影响管道的读取?
【问题讨论】:
-
为什么你认为关闭fd[1]两次就可以了?
-
在第一个示例中,您在 fork 第二个孩子之前关闭了管道的写入端,这样孩子就无法写入管道。你通过移动关闭来修复它。有什么问题?
-
啊,我明白了。谢谢,我忘了老二会写完结的!
-
您应该始终测试
write的返回计数。特别是对于管道和套接字,partialwrite确实会发生