Unix 系统调用:read/write 和缓冲区
Unix system calls : read/write and the buffer
我正在编写一个非常简单的脚本。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
int pipefd[2];
pid_t c;
int value[2];
c = fork();
if(c<0){
perror("in fork");
exit(1);
}
if(c==0){
printf("i am the child\n");
int buf[2];
buf[0]=3;
buf[1]=0;
write(pipefd[1], buf, 4);
write(pipefd[1],buf+1,4);
close(pipefd[1]);
exit(0);
}
if (pipe(pipefd) == -1) { /*UPDATE */
perror("pipe");
exit(EXIT_FAILURE);
}
read(pipefd[0], value, 4);
read(pipefd[0], value+1, 4);
close(pipefd[0]);
printf("%d %d\n", value[0], value[1]);
exit(0);
}
我打算做的是实现:
值[0] = buf[0];
值[1] = buf[1];
(当然还要打印出来)。
但我得到的结果是:
-1299582208 32766
i am the child
因为我有整数,所以我假设每个整数都包含 4 个字节。而且我认为对于一个 int 数组,每个元素将包含 4 个字节。但显然我错过了一些东西。有帮助吗?
一个非常简单的解决方法是在 read()
调用之上放置一个 sleep(1)
调用 - 显然这不是一个很好的解决方案。
多进程编程和通信的一个重要的早期教训是“竞争条件”。看来,您的 child 分支在 parent 之前执行。我敢打赌,如果你 运行 这 20 次,你可能会得到 X 次它做你想做的事!
你无法保证运行执行顺序。因此,在您学习有关资源锁定(互斥锁、信号量)的更高级技术之前,sleep(1) 就足够了。
正如我在置顶评论中提到的:pipe
系统调用在哪里?
没有它,write
和 read
调用可能会失败,因为 pipefd
有 运行dom 值。
因此,parent 永远不会 value
正确填写。
因为这些 [unitialized] 值在堆栈上,它们将具有 运行dom 值,这就是您所看到的。
这是 UB [未定义的行为]。
不同的 systems/compilers 可能会以不同的方式操作堆栈,这就是为什么您看到 不同的 [但仍然 运行dom] 在不同的配置上的结果。
要修复,请在 上方 您的 fork
调用中添加以下内容:
pipe(pipefd);
我下载、构建并 运行 您的程序。在添加修复程序之前,我得到了 运行dom 值。应用修复后,我得到 3 0
作为输出,这就是你 expected/wanted.
注意: 正如其他人提到的,您可以检查 read
和 write
的 return 代码。如果你有,他们可能会 return -1
并在 errno
中放入一个错误代码,这将帮助你调试问题。
我正在编写一个非常简单的脚本。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
int pipefd[2];
pid_t c;
int value[2];
c = fork();
if(c<0){
perror("in fork");
exit(1);
}
if(c==0){
printf("i am the child\n");
int buf[2];
buf[0]=3;
buf[1]=0;
write(pipefd[1], buf, 4);
write(pipefd[1],buf+1,4);
close(pipefd[1]);
exit(0);
}
if (pipe(pipefd) == -1) { /*UPDATE */
perror("pipe");
exit(EXIT_FAILURE);
}
read(pipefd[0], value, 4);
read(pipefd[0], value+1, 4);
close(pipefd[0]);
printf("%d %d\n", value[0], value[1]);
exit(0);
}
我打算做的是实现:
值[0] = buf[0]; 值[1] = buf[1];
(当然还要打印出来)。
但我得到的结果是:
-1299582208 32766
i am the child
因为我有整数,所以我假设每个整数都包含 4 个字节。而且我认为对于一个 int 数组,每个元素将包含 4 个字节。但显然我错过了一些东西。有帮助吗?
一个非常简单的解决方法是在 read()
调用之上放置一个 sleep(1)
调用 - 显然这不是一个很好的解决方案。
多进程编程和通信的一个重要的早期教训是“竞争条件”。看来,您的 child 分支在 parent 之前执行。我敢打赌,如果你 运行 这 20 次,你可能会得到 X 次它做你想做的事!
你无法保证运行执行顺序。因此,在您学习有关资源锁定(互斥锁、信号量)的更高级技术之前,sleep(1) 就足够了。
正如我在置顶评论中提到的:pipe
系统调用在哪里?
没有它,write
和 read
调用可能会失败,因为 pipefd
有 运行dom 值。
因此,parent 永远不会 value
正确填写。
因为这些 [unitialized] 值在堆栈上,它们将具有 运行dom 值,这就是您所看到的。
这是 UB [未定义的行为]。
不同的 systems/compilers 可能会以不同的方式操作堆栈,这就是为什么您看到 不同的 [但仍然 运行dom] 在不同的配置上的结果。
要修复,请在 上方 您的 fork
调用中添加以下内容:
pipe(pipefd);
我下载、构建并 运行 您的程序。在添加修复程序之前,我得到了 运行dom 值。应用修复后,我得到 3 0
作为输出,这就是你 expected/wanted.
注意: 正如其他人提到的,您可以检查 read
和 write
的 return 代码。如果你有,他们可能会 return -1
并在 errno
中放入一个错误代码,这将帮助你调试问题。