使用 execl 创建的子进程不接受任何输入

child process created using execl is not accepting any input

我写了一个程序,它首先复制当前进程(使用 fork()),然后我使用 execl() 创建一个子进程。

现在的问题是子进程无法接受任何输入。

child.c 程序:

#include<stdio.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
    int p, pp;
    int a;
    char dummy;
    printf("\n enter value of a \n");
    //fflush(0); // was using to clean STDIN, STDOUT
    //fflush(1);
    scanf("%c",&dummy); // simply using to accept any new line character if present any.
    scanf("%c",&dummy); // simply using to accept any new line character if present any.
    scanf("%d",&a);
    p = getpid();
    pp = getppid();
    printf("\nI m child with pid %d and ppid %d \n", p, pp);
    char *msg = argv[1];
    printf("\n Message from parent is %s \n",msg);
    printf("\n The value of a is %d ",a);
    return 0;
}

我正在使用以下命令编译我的 child.c:gcc child.c -o child 以生成名称为 child 的目标文件,我将在我的 parent.c 文件[=20]中使用它=]

我的parent.c程序:

#include<stdio.h>
#include<unistd.h>

int main()
{
    int p, pp;
    p = getpid();
    pp = getppid();
    printf("\nI m parent with pid %d and ppid %d \n", p, pp);
    int b = fork();
    if (b == 0)
    {
        sleep(1);// for orphan state
        execl("./child", "child", "hello", 0);
    }
    else
    {
        printf("\nBye\n");
    }
    return 0;
}

我已经尝试运行将程序设置为孤儿状态和僵尸状态,但在这两种情况下,子进程都没有接受输入。

当我 运行 这个父程序的 ./a.out 时,我得到以下输出:

I m parent with pid 6801 and ppid 4136

Bye [aupadhyay@localhost practice]$ enter value of a

I m child with pid 6802 and ppid 1

Message from parent is hello

The value of a is 0

控制台不接受任何输入,而是打印 a 的默认值。

任何关于如何在子进程中获取输入的information/help将不胜感激。

注意:根据@Gilles 的编辑和评论对答案进行了重大修改。

尽管我可以复制您描述的行为,但我也可以通过 I/O 重定向将输入提供给 child:

./parent <<EOF


12345
EOF

...导致:

I m parent with pid 4430 and ppid 2515

Bye

$

enter value of a

I m child with pid 4431 and ppid 1

Message from parent is hello

The value of a is 12345

请注意,重定向到 parent 标准输入的数据已被 child 成功读取和回显,因此问题不在于 child 无法接受输入。在某些情况下,它 不会 等待或成功读取输入,而是继续进行读取尝试,只能通过在这些情况下失败的 scanf() 调用来解释。

对此类失败最合理的解释是在尝试读取时进程组已移至后台。通常,试图从其控制终端读取的后台进程将导致其整个进程组停止(而不是终止)。但是,在您的情况下,进程组是 orphaned:组中没有进程在会话内但在组外具有 parent。在这种情况和其他一些特殊情况下,后台进程的 read() 来自其控制终端,例如您的 scanf() 调用,are required to fail, setting errno to EIO.

在那种情况下,scanf 依次 returns EOF 指示错误,将 errno 设置为 EIO。测试 scanf 的 return 值并调用 perror 观察这一点。读取失败是一种明智的行为,因为它们有助于孤立组 运行 中的进程完成和终止,而不是挂起或 OS 立即杀死它们。 POSIX 的 objective 似乎是为进程组提供优雅的处理,这些进程组因 parent 即 job-control shell 的终止而孤立,留下没有期望或责任重新启动进程组的进程。

你的情况不是 POSIX 似乎有意迎合的,但规范也支持观察到的行为:shell 将前台进程组转移到后台,当它的领导者死了,但(似乎)没有将其作为背景 job 置于作业控制之下。据我所知,POSIX 没有强制要求 shell 表现出这种行为,但也没有其他要求。结果是一个孤儿进程组,其情况与 POSIX 所设想的情况相似,并且同样受到针对孤儿进程组的特殊规定的支持。

如果您希望 child 保留对 parent 控制终端的完全访问权限,那么您应该确保 parent 不会在 child 之前终止做。如果 parent 在此期间无事可做,确保 child 首先终止的适当方法是 parent 到 wait()waitpid()为此:

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

int main()
{
    int p, pp;
    p = getpid();
    pp = getppid();
    printf("\nI m parent with pid %d and ppid %d \n", p, pp);
    int b = fork();
    if (b == 0)
    {
        execl("./child", "child", "hello", 0);
    }
    else
    {
        printf("\nBye\n");
        wait(NULL);
    }
    return 0;
}