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 系统调用在哪里?

没有它,writeread 调用可能会失败,因为 pipefd 有 运行dom 值。

因此,parent 永远不会 value 正确填写。

因为这些 [unitialized] 值在堆栈上,它们将具有 运行dom 值,这就是您所看到的。

这是 UB [未定义的行为]。

不同的 systems/compilers 可能会以不同的方式操作堆栈,这就是为什么您看到 不同的 [但仍然 运行dom] 在不同的配置上的结果。

要修复,请在 上方 您的 fork 调用中添加以下内容:

pipe(pipefd);

我下载、构建并 运行 您的程序。在添加修复程序之前,我得到了 运行dom 值。应用修复后,我得到 3 0 作为输出,这就是你 expected/wanted.

注意: 正如其他人提到的,您可以检查 readwrite 的 return 代码。如果你有,他们可能会 return -1 并在 errno 中放入一个错误代码,这将帮助你调试问题。