管道中父进程的 wait() 有什么问题
What is wrong with wait() on father process in pipeline
有人问我:
- 下一段代码有什么问题?
- 如何在儿子的进程代码中修复它:
#define BUF_SIZE 4096
int my_pipe[2];
pipe(my_pipe);
char buf[BUF_SIZE];
int status = fork();
//Filled buf with message...
if (status == 0) { /* son process */
close(my_pipe[0]);
write(my_pipe[1],buf,BUF_SIZE*sizeof(char));
exit(0);
}
else { /* father process */
close(my_pipe[1]);
wait(&status); /* wait until son process finishes */
read(my_pipe[0], buf, BUF_SIZE*sizeof(char));
printf("Got from pipe: %s\n", father_buff);
exit(0);
}
}
所以我想出了下一个代码来尝试解决这个问题:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#define BUF_SIZE 6
int main() {
int my_pipe[2];
pipe(my_pipe);
char buf[BUF_SIZE];
int status = fork();
//Filled buf with message...
for (int i = 0; i < BUF_SIZE; i++) buf[i] = 'a';
if (status == 0) { /* son process */
close(my_pipe[0]);
write(my_pipe[1], buf, BUF_SIZE * sizeof(char));
_exit(0);
} else { /* father process */
close(my_pipe[1]);
wait(&status); /* wait until son process finishes */
printf("Son Status: %d\n", status);
read(my_pipe[0], buf, BUF_SIZE * sizeof(char));
printf("Got from pipe: %s\n", buf);
_exit(0);
}
}
我的第一个想法是 wait(&status)
有问题,如果子进程无法完成,可能会导致程序无法终止。
在儿子的代码中,我相信如果管道中没有足够的 space,write
将阻塞进程,从而阻塞整个应用程序。
如果我的说法是正确的,我该如何证明呢?而且我没有弄清楚如何修复儿子的代码。
您对管道尺寸的假设是正确的,我可以用 BUF_SIZE
重现问题 0x10000
。
但解决办法不在客户,而在家长。您只需在 wait()
之前输入 read()
,当然您应该始终使用 return 代码来确定您收到了多少。父项的此修复不再导致阻塞:
len = read(my_pipe[0], buf, BUF_SIZE * sizeof(char));
if( len >= 0 ) {
printf("Got %d from pipe\n", len );
} else {
perror( "read()" );
}
close(my_pipe[1]);
wait(&status); /* wait until son process finishes */
printf("Son Status: %d\n", status);
在子进程中,您可以使用 fcntl(my_pipe[1], F_SETFL, O_NONBLOCK);
使用非阻塞 IO,因此 write()
会发送尽可能多的数据,然后 return。当然,在这种情况下,其余数据将丢失。
有人问我:
- 下一段代码有什么问题?
- 如何在儿子的进程代码中修复它:
#define BUF_SIZE 4096
int my_pipe[2];
pipe(my_pipe);
char buf[BUF_SIZE];
int status = fork();
//Filled buf with message...
if (status == 0) { /* son process */
close(my_pipe[0]);
write(my_pipe[1],buf,BUF_SIZE*sizeof(char));
exit(0);
}
else { /* father process */
close(my_pipe[1]);
wait(&status); /* wait until son process finishes */
read(my_pipe[0], buf, BUF_SIZE*sizeof(char));
printf("Got from pipe: %s\n", father_buff);
exit(0);
}
}
所以我想出了下一个代码来尝试解决这个问题:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#define BUF_SIZE 6
int main() {
int my_pipe[2];
pipe(my_pipe);
char buf[BUF_SIZE];
int status = fork();
//Filled buf with message...
for (int i = 0; i < BUF_SIZE; i++) buf[i] = 'a';
if (status == 0) { /* son process */
close(my_pipe[0]);
write(my_pipe[1], buf, BUF_SIZE * sizeof(char));
_exit(0);
} else { /* father process */
close(my_pipe[1]);
wait(&status); /* wait until son process finishes */
printf("Son Status: %d\n", status);
read(my_pipe[0], buf, BUF_SIZE * sizeof(char));
printf("Got from pipe: %s\n", buf);
_exit(0);
}
}
我的第一个想法是 wait(&status)
有问题,如果子进程无法完成,可能会导致程序无法终止。
在儿子的代码中,我相信如果管道中没有足够的 space,write
将阻塞进程,从而阻塞整个应用程序。
如果我的说法是正确的,我该如何证明呢?而且我没有弄清楚如何修复儿子的代码。
您对管道尺寸的假设是正确的,我可以用 BUF_SIZE
重现问题 0x10000
。
但解决办法不在客户,而在家长。您只需在 wait()
之前输入 read()
,当然您应该始终使用 return 代码来确定您收到了多少。父项的此修复不再导致阻塞:
len = read(my_pipe[0], buf, BUF_SIZE * sizeof(char));
if( len >= 0 ) {
printf("Got %d from pipe\n", len );
} else {
perror( "read()" );
}
close(my_pipe[1]);
wait(&status); /* wait until son process finishes */
printf("Son Status: %d\n", status);
在子进程中,您可以使用 fcntl(my_pipe[1], F_SETFL, O_NONBLOCK);
使用非阻塞 IO,因此 write()
会发送尽可能多的数据,然后 return。当然,在这种情况下,其余数据将丢失。