为什么fflush()会影响分叉进程的输出?

时间:2015-09-01 12:10:39

标签: c operating-system buffer fork system-calls

我正在尝试学习UNIX编程并遇到有关taxAmount的问题,我无法解释下面两个程序的输出。

我理解fork()创建了一个当前正在运行的进程的相同进程,但是它从哪里开始?例如,如果我有以下这两个程序,那么输出是什么以及它是如何工作的?

fork()

以上程序和下面的程序有什么不同 尊重子流程执行:

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

int main (int argc, char **argv)
{
    int retval;
    printf ("This is most definitely the parent process\n");
    // now here fork will create a child process 
    // i need to know from which line child process starts execution 

    retval = fork ();
    printf ("Which process printed this?\n");

    return (0);
}

我认为他们都应该打印出来:

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

int main (int argc, char **argv)
{
    int retval;
    printf ("This is most definitely the parent process\n");

    fflush (stdout);
    // how does fflush change the output of above program and why ?
    // even though no string operations are being used
    retval = fork ();
    printf ("Which process printed this?\n");

    return (0);
 }

但第一个是印刷:

This is most definitely the parent process 
Which process printed this? 
Which process printed this? 

3 个答案:

答案 0 :(得分:3)

  

我知道fork()创建了一个与当前相同的进程   运行过程,但它从哪里开始?

如果fork(2)成功(即不返回-1),则会从调用fork(2)的行开始。 fork(2)返回两次:它在子项中返回0,在父项中返回正数C,其中C是新生儿的进程ID。

你看到的原因这绝对是父进程两次与stdio的缓冲有关。 Stdio缓冲用户空间缓冲区中的输出,这些缓冲区仅在发生某些条件时刷新(例如,缓冲区变满)。缓冲模式决定了刷新缓冲区的时间和方式。

通常,如果将输出写入交互设备(如终端(或伪终端)),则stdio是行缓冲,这意味着在找到换行符时刷新缓冲区或{ {1}}被调用。

OTOH,如果输出被重定向到文件或其他非交互设备(例如,输出被重定向到管道),则stdio 完全缓冲,这意味着只刷新缓冲区当它们变满或被叫fflush(3)时。

因此,如果没有fflush(3),在终端设备中执行代码将打印出来:

fflush(3)

预期。但是,如果你通过This is most definitely the parent process Which process printed this? Which process printed this? 管道,你会看到这个(或其他一些变体,取决于执行顺序):

cat(1)

这是因为重定向到管道时输出完全缓冲。字符串This is most definitely the parent process Which process printed this? This is most definitely the parent process Which process printed this? 不足以填充和刷新缓冲区,因此当父分叉时,子代(获取父代的内存空间的副本)将获得输出缓冲区的副本,该缓冲区已包含字符串This is most definitely the parent process。因此,两个进程最终都会打印该字符串。

如果你总是在分叉之前调用This is most definitely the parent process,那么这不会发生,因为当父母的内存空间被复制到孩子时,缓冲区是空的。

答案 1 :(得分:0)

执行将在fork调用(或之后)继续执行。您可以使用返回值来检查您是父进程还是子进程:

  

返回值
         成功时,子进程的PID将在父进程中返回,并返回0          在孩子身上失败时,在父项中返回-1,不创建子进程,          和errno设置得恰当。

(来源:man fork

例如,如果您有以下程序:

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

int main(int argc, char **argv) {
    printf("Foo.\n");
    int retval = fork();
    printf("Bar from %s (%d).\n", (retval == 0) ? "child" : "parent", retval);
    return 0;
}

输出类似于:

Foo.
Bar from parent (18464).
Bar from child (0).

...假设输出是行缓冲的。

答案 2 :(得分:0)

在致电for (int i = 0; i < random.Length; i++) { if (guessBool [i]) guessChar += random[i] + " "; else guessChar += "_ "; } GetComponent<TextMesh> ().text = guessChar; 时,有三种可能的退货条件。

请阅读fork()

的手册页

三个返回条件是

fork()

代码必须是这样的:

-1 -- the fork() failed
 0 -- the child is executing
some positive number -- the pid of the child, the parent is executing