【问题标题】:The behavior of the fork() system call on Linux in this code [duplicate]此代码中 Linux 上 fork() 系统调用的行为 [重复]
【发布时间】:2015-04-23 10:03:36
【问题描述】:

我在书籍和在线资源中读到 fork() 系统调用会创建当前进程的副本,并且两个进程都从进行 fork() 系统调用后的那一点开始执行。对吗?

如果正确,为什么下面的代码会打印“Test Test”?它应该只打印一次“测试”(由父进程)。

#include <sys/types.h> /* pid_t */
#include <sys/wait.h>  /* waitpid */
#include <stdio.h>     /* printf, perror */
#include <stdlib.h>    /* exit */
#include <unistd.h>    /* _exit, fork */


int main(void)
{
    int ctr =1;
    int pc = 1;
    printf("%s", "Test ");
    pid_t pidmain = fork();
    return EXIT_SUCCESS;
}

【问题讨论】:

  • 在“test”字符串中添加一个“\n”。
  • @wildplasser 添加 \n 后令人惊讶的是,我得到了测试(单次)而不是 2 次。但为什么呢?
  • 标准输出的行缓冲。程序的 fork() d 副本在标准输出上都有一个半填充的缓冲区,该缓冲区在程序退出时被刷新。 (两个出口)。为了证明这一点,您还可以在 fork() 之前添加 sleep(1)
  • @wallyk 我会说这是一个公平的重复。

标签: c linux fork


【解决方案1】:

当您调用fork() 时,操作系统会创建当前进程整个内存的副本(它实际上并不复制内存,因为它可以使用 MMU 有效地执行此操作)。

由于标准输出默认是缓冲的,它只会在写入换行符或刷新流时打印消息。当您分叉一个新进程时,当前的写入缓冲区(包含“Test”)也将在新进程中复制。一旦进程退出,这将被打印出来,因为这会隐式关闭(并刷新)stdout。 如果您将printf("%s", "Test "); 替换为printf("%s\n", "Test "); 或在fork() 之前添加fflush(stdout); 调用,您将看到预期的输出。

【讨论】:

  • 或者如果 C 库决定缓冲区中的内容开始过多...依赖缓冲区中剩余的输出并在 fork 调用期间被复制是错误的。
【解决方案2】:

在您调用 fork 时,两个进程的缓冲区中都有字符串“Test”用于标准输出。当每个进程退出时,它们都会将此文本刷新到输出(请参阅exit 以获得解释)。您可以(如建议的那样)在缓冲区中添加一个换行符(由于缓冲,它会碰巧出现——请参阅setbuf 以获取解释)。或者你可以在 fork 之前调用 fflush(stdout) 并得到你想要的——“Test”字符串。

【讨论】:

  • 感谢您指出有用的链接。
猜你喜欢
  • 1970-01-01
  • 2015-12-22
  • 2012-06-26
  • 2011-10-03
  • 1970-01-01
  • 2016-04-30
  • 2017-04-12
  • 2014-12-13
  • 2021-09-05
相关资源
最近更新 更多