在C语言中,fork出的进程中如果在scanf之前调用了Printf函数会发生什么?

3
我遇到了一个问题,使用scanf在fork()函数创建的新进程中。scanf没有被阻塞,因此printf会一遍又一遍地调用。

以下是代码示例:

int main(int argc,char *argv[])
{
    switch(fork()) {
        case 0:
            while(1) {
                char buffer[100];
                scanf("%s",buffer);
                printf("Input was %s\n",buffer);
            }
    }
    return 0;
}

有人知道如何解决这个简单的问题吗?(代码中有一些部分缺失,我为了这个问题将代码缩小到最小程度)


你的新进程没有任何接口,所以scanf无法扫描。 - Sarima
我该如何将接口附加到它上面?@Joshpbarron - user5654873
为什么不在父进程中扫描? - Boiethios
当调用fork()时,子进程需要调用exit(),而父进程在子进程之前不能退出。如果父进程先退出,则子进程会变成“僵尸”进程。僵尸进程很难在不重新启动计算机的情况下终止。建议在父进程中调用wait()waitpid(),以便父进程在子进程之前不会退出。请记住,fork()返回3种不同的条件,代码必须允许所有三种条件。 - user3629249
当使用 %s 格式说明符调用 scanf() 时,始终包括一个 max characters 修饰符,以便输入不会超出输入缓冲区。这样的输入缓冲区溢出会导致未定义的行为,并可能导致段错误事件。 - user3629249
显示剩余2条评论
2个回答

1
问题出在你注释掉的代码上,为了制作最小示例而注释掉的代码,在运行时完全正常。
#include <stdio.h>

int main(int argc,char *argv[])
{
    switch(fork()) {
        case 0:
            while(1) {
                char buffer[100];
                scanf("%s",buffer);
                printf("Input was %s\n",buffer);
            }
            break;
        default:
            sleep(100);
            break;
    }
    return 0;
}

我的猜测是,在您的fork调用周围有一些关闭文件来创建子进程并将其从终端中分离的操作,正是关闭标准输入和从终端中分离导致了您的scanf失败。

1
分叉没有与终端分离,但是shell重新打开一个新的stdin来读取下一个命令,之前的命令已经关闭。 - Serge Ballesta
是的 - fork本身不会关闭任何东西 - 我指的是他已经注释掉的代码部分 - 我会尝试看看是否可以澄清。 - Soren

0

真正的问题在于父进程立即返回。然后,shell接管标准输入以读取新命令。您可以通过在父进程中添加短暂的睡眠来轻松演示它:

switch(fork()) {
    case 0: 
        while(1) {
            char buffer[100];
            int cr = scanf("%s",buffer);
            printf("Input was %s (%d)\n",buffer, cr);
            if (cr <= 0) break;
        }
    }
    break;
default:
    sleep(5);
    printf("Done\n");
}

在父进程休眠的5秒钟内,您通常可以与子进程进行交互。然后当父进程退出时,子进程的输入将被关闭,scanf函数将返回-1。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接