【问题标题】:Different outputs with fork()fork() 的不同输出
【发布时间】:2012-08-15 04:15:23
【问题描述】:

谁能解释为什么输出

main()   
{   
    printf("hello ");   
    fork();   
    printf("hello ");   
}

是:

你好你好你好你好

和输出:

main()   
{   
    printf("hello\n");   
    fork();   
    printf("hello ");   
}

是:

你好
你好你好

\n 对缓冲有什么不同?

【问题讨论】:

    标签: c fork system-calls


    【解决方案1】:

    当你fork 时,进程的内存被复制。这包括stdio 缓冲区,因此如果hello 留在缓冲区中,它将被两个进程打印。两个进程都继续他们的业务并最终刷新他们的缓冲区,你会看到两次“hello”。

    现在在大多数实现中标准输出是行缓冲的,这意味着\n 会触发刷新。所以当fork 发生时,缓冲区是空的。防止这种情况的可靠方法是在分叉之前冲洗所有内容。

    编辑

    那么为什么hello在第二行的第二行出现了两次 输出

    现在有两个进程(父进程和子进程)执行相同的代码,因此printf 会执行两次。

    【讨论】:

    • 那么为什么hello在第二个输出的第二行出现了两次呢?
    【解决方案2】:

    虽然 cnicutar 的回答描述了常见实现中发生的事情背后的机制,但核心问题是您的程序正在调用未定义的行为。 POSIX 规定了为打开文件切换“活动句柄”的规则:

    http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_05_01

    fork 是文件的新句柄出现的一种情况,除非您已准备好在fork 之前切换活动句柄,否则在fork 之后同时使用它们是未定义的行为:

    请注意,在 fork() 之后,存在两个句柄,而之前存在一个句柄。应用程序应确保,如果两个句柄都可以访问,则它们都处于另一个可以首先成为活动句柄的状态。应用程序应为 fork() 做好准备,就像它是活动句柄的更改一样。 (如果其中一个进程执行的唯一操作是 exec 函数或 _exit()(不是 exit())之一,则永远不会在该进程中访问句柄。)

    【讨论】:

    • 换句话说,缓冲区需要为空——即:需要刷新句柄——在分叉之前,或者它是UB。在第二个示例中,\n 触发了刷新……但在第一个示例中没有这样做。
    • \n 仅在 stdout 是行缓冲时才会触发刷新,这仅在您将其显式设置为行缓冲或它是终端时才会发生。
    猜你喜欢
    • 2012-03-10
    • 1970-01-01
    • 2018-05-11
    • 1970-01-01
    • 2012-01-12
    • 2012-10-04
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多