【问题标题】:pipe examples between child and parent in Linux CLinux C中子与父之间的管道示例
【发布时间】:2021-04-11 04:25:44
【问题描述】:

这看起来很简单,一个管道,父级将在管道的写入端写入管道,子级将在while循环中从管道读取,并打印读取的内容,但我的程序未能停止...

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int
main(int argc, char *argv[]){
  int fd[2];
  int number;
  int write_number[1];
  pipe(fd);
  int pid;
  if ((pid = fork()) >0){
     close(fd[0]);
     for (int i = 2; i < 36; i++){
         *write_number = i;
         write(fd[1], write_number, 4);
     }
     printf("write finished from parent process:%d\n", pid);
     close(fd[1]);
  }else{// child process
     close(fd[1]);
     while(read(fd[0], &number, 4))
        printf("The number is %d from child %d\n", number, getpid());
     close(fd[0]);
  }
  exit(0);
}

顺便说一句,这是来自 xv6 类 Unix 系统,但我认为这与在 Linux 中几乎相同,输出:

$ primes
The numbwerite finished from parent prorc eis ss:24
 from $ child 4
The number is 3 from child 4
The number is 4 from child 4
The number is 5 from child 4
The number is 6 from child 4
The number is 7 from child 4
The number is 8 from child 4
The number is 9 from child 4
The number is 10 from child 4
The number is 11 from child 4
The number is 12 from child 4
The number is 13 from child 4
The number is 14 from child 4
The number is 15 from child 4
The number is 16 from child 4
The number is 17 from child 4
The number is 18 from child 4
The number is 19 from child 4
The number is 20 from child 4
The number is 21 from child 4
The number is 22 from child 4
The number is 23 from child 4
The number is 24 from child 4
The number is 25 from child 4
The number is 26 from child 4
The number is 27 from child 4
The number is 28 from child 4
The number is 29 from child 4
The number is 30 from child 4
The number is 31 from child 4
The number is 32 from child 4
The number is 33 from child 4
The number is 34 from child 4
The number is 35 from child 4

它没有停止,所以它挂起,但是我已经关闭了我应该关闭的文件描述符,所以如果没有读取任何内容,read 系统调用应该返回 0,为什么它仍然挂起,所以任何人都可以帮我一把?谢谢!

【问题讨论】:

  • 你有没有试过在最后一次输出后按Enter键?你得到你的提示了吗?然后是因为父进程退出(早在子进程之前)并且shell重新获得了控制权。然而,子进程还没有完成并继续写入输出。在读取循环之后添加一个额外的输出来验证(除了Enter 键检查)。
  • 我最初的想法是parent会一个接一个的往管道里写入一系列整数,child会一个接一个地从管道中读取,读完后我关闭相关文件描述符,当文件描述符全部关闭时,意味着文件结束,所以不需要按回车键,我只是想验证我的想法是否可行......但似乎有问题

标签: c pipe


【解决方案1】:

它确实停止了——在孩子打印“孩子 4 的数字是 3”之前,父母退出并在混乱的输出中从 shell 产生提示:

$ primes
The numbwerite finished from parent prorc eis ss:24
 from $ child 4
The number is 3 from child 4

您可能应该使用wait()waitpid() 函数让父进程在循环中等待,以便子进程在父进程退出并且shell 重新提示之前完成。

#include <sys/wait.h>

…

int status;
int corpse;
while ((corpse = wait(&status)) > 0)
    print("Child %d died with exit status 0x%.4X\n", corpse, status);

虽然不太可能,但进程可能会产生当前程序没有派生的子进程,并且循环也可以在这种情况下正常工作。

切线注释:

  1. 由于忽略命令行参数,最好使用int main(void)

  2. exit(0); 不是必需的。您可以省略它,如果您在 C99 或更高版本的模式下编译,该过程将以零退出。这只是main() 函数的特例规则。就个人而言,我更喜欢在main() 的末尾使用显式的return 0;

  3. 你有:

     for (int i = 2; i < 36; i++){
         *write_number = i;
         write(fd[1], write_number, 4);
     }
    

你可以使用:

    for (int i = 2; i < 36; i++)
        write(fd[1], &i, sizeof(i));

使用sizeof() 是惯用的;使用4 容易出错。并且不需要write_number 数组。

  1. 标题的选择是常规的。您应该使用&lt;stdio.h&gt;&lt;unistd.h&gt;&lt;sys/wait.h&gt;。你实际上并不需要&lt;sys/types.h&gt;。内核头文件只应在编译代码以在内核中运行时使用——该程序不是内核代码。

你说:

我添加了一些类似printf("child process is finished")的代码,在child条件下,它打印,但是exit(0)之前没有wait(0),这意味着子进程没有问题,它会等待从管道关闭,但最后程序没有完成,只是挂在那里似乎在等待输入,我认为这是父母退出但不等待孩子退出()的情况,但孩子确实在结束,但他的程序没有完成....最后的混乱

IMO,您的代码应如下所示:

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

int main(void)
{
    int fd[2];
    pipe(fd);
    int pid;
    if ((pid = fork()) > 0)
    {
        close(fd[0]);
        for (int i = 2; i < 36; i++)
            write(fd[1], &i, sizeof(i));
        close(fd[1]);
        printf("write finished from parent process:%d\n", pid);
        int status;
        int corpse;
        while ((corpse = wait(&status)) > 0)
        {
            printf("%d: child %d exited with status 0x%.4X\n",
                   (int)getpid(), corpse, status);
        }
    }
    else if (pid < 0)
    {
        fprintf(stderr, "failed to fork\n");
        return 1;
    }
    else
    {
        int number;
        close(fd[1]);
        while (read(fd[0], &number, sizeof(number)) > 0)
            printf("The number is %d from child %d\n", number, getpid());
        close(fd[0]);
    }
    return 0;
}

我得到的一个示例输出(在运行 macOS Big Sur 11.2.3 的 MacBook Pro 上运行)是:

write finished from parent process:53072
The number is 2 from child 53072
The number is 3 from child 53072
The number is 4 from child 53072
The number is 5 from child 53072
The number is 6 from child 53072
The number is 7 from child 53072
The number is 8 from child 53072
The number is 9 from child 53072
The number is 10 from child 53072
The number is 11 from child 53072
The number is 12 from child 53072
The number is 13 from child 53072
The number is 14 from child 53072
The number is 15 from child 53072
The number is 16 from child 53072
The number is 17 from child 53072
The number is 18 from child 53072
The number is 19 from child 53072
The number is 20 from child 53072
The number is 21 from child 53072
The number is 22 from child 53072
The number is 23 from child 53072
The number is 24 from child 53072
The number is 25 from child 53072
The number is 26 from child 53072
The number is 27 from child 53072
The number is 28 from child 53072
The number is 29 from child 53072
The number is 30 from child 53072
The number is 31 from child 53072
The number is 32 from child 53072
The number is 33 from child 53072
The number is 34 from child 53072
The number is 35 from child 53072
53069: child 53072 exited with status 0x0000

如果输出通过管道传输到另一个程序,“write finished from parent process:53072”行会出现在“退出”打印之前的末尾。

【讨论】:

  • 是的,你的分析是合理的,我“错误地”在exit(0)之前添加了等待,所以我的程序按预期完成了……但我不打算添加等待(0)在退出(0)之前,我希望孩子会自动退出,所以为什么我添加等待(),它会起作用,否则不是?你能解释更多吗?谢谢!
  • 在您的exit(0); 之前添加wait(0) 在父母和孩子中实现不同的结果。我忽略了继承孩子的古怪案例。在子进程中,wait(0) 调用失败,因为子进程没有自己的子进程,报告 ECHILD(没有子进程)。在父母中,该过程一直等到孩子死亡,但您对信息没有任何进一步的处理。但是父级在子级死亡之前并没有退出,所以子级的输出出现了,然后父级才退出。在父级打印其消息之前放置wait() 可能会更好。
  • 我加了一些类似printf("child process is finished")的代码,在child条件下打印,但是exit(0)之前没有wait(0),表示子进程没有问题,它会等待从管道关闭,但最后程序没有完成,只是挂在那里似乎在等待输入,我认为这是父退出但不等待子退出()的情况,但是孩子最后确实退出了,但他的程序没有完成....最后的混乱
  • 我只在exit(0)前加上//wait(0),和printf("child is finished") after child while loop
猜你喜欢
  • 1970-01-01
  • 2015-01-18
  • 2017-08-26
  • 2014-03-07
  • 2019-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多