簡體   English   中英

為什么fflush()影響分叉進程的輸出?

[英]Why does fflush() affect the output of forked processes?

我正在嘗試學習UNIX編程,並且遇到了一個有關fork()的問題,但我無法解釋下面2個程序的輸出。

我知道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? 

但是第一個是打印:

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

我知道fork()創建的進程與當前正在運行的進程相同,但是它從哪里開始?

如果fork(2)成功(即不返回-1 ),它將從調用fork(2)的行開始。 fork(2)返回兩次:它在子代中返回0,在父代中返回正數C ,其中C是新生代的進程ID。

您看到的原因這肯定是父進程兩次,都與stdio的緩沖有關。 用戶空間緩沖區中的Stdio緩沖區輸出僅在某些情況下(例如,緩沖區變滿)才刷新。 緩沖模式指示何時以及如何刷新緩沖區。

通常,如果將輸出寫入交互式設備(例如終端(或偽終端)),則stdio將被行緩沖 ,這意味着當找到換行符或調用fflush(3)時,將刷新緩沖區。

OTOH,如果將輸出重定向到文件或其他非交互式設備(例如,將輸出重定向到管道),則stdio將被完全緩沖 ,這意味着僅在緩沖區變滿或fflush(3)被刷新時才刷新緩沖區調用。

因此,如果沒有fflush(3) ,則在終端設備中執行代碼將顯示以下內容:

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

這是預期的。 但是,如果將其通過cat(1)管道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 processThis is most definitely the parent process的內存空間的副本)將獲得輸出緩沖區的副本,該輸出緩沖區已經包含字符串。 This is most definitely the parent process 因此,這兩個過程最終都會打印該字符串。

如果您始終在派生之前調用fflush(3) ,則不會發生這種情況,因為將父級的內存空間復制到子級時緩沖區為空。

執行將在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).

...假設輸出是行緩沖的。

調用fork() ,有三種可能的返回條件。

請閱讀fork()的手冊頁

三個返回條件是

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

代碼需要是這樣的:

pid_t pid;

pid = fork();
if ( 0 > pid ) 
{ // then handle error
}
else if ( 0 == pid )
{ // then child executing
}
else // if ( 0 < pid )
{ // then parent executing
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM