2013-01-22 57 views
4

我正在學習與fork()一起工作,並且我有一些問題。爲什麼分叉時在終端和文件之間有不同的輸出?

考慮下面的代碼:

#include <stdio.h> 
#include <unistd.h> 

int main() 
{ 
    int i; 

    for(i = 0; i < 5; i++) 
    { 
     printf("%d", i); 

     if((i%2)==0) 
     if(fork()) 
      fork(); 
    } 
} 

當我輸出到終端,我得到的結果,我希望(即:0,1,1,1,2,2,2,...)。但是,當我輸出到文件,結果是完全不同:

  • 例1:(輸出到終端,例如:./a.out):

    結果是:0,1,1,1,2,2,2,...

  • 情況2: (輸出到文件,例如:./a.out > output_file

    結果是:0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,...

這是爲什麼?

+0

「完全不同」是什麼意思?你瞭解多處理,多個進程在同一時間工作嗎? –

+0

不同的結果是什麼? – imreal

+0

我們需要更多的代碼。你如何寫你的文件?文件上顯示的輸出是什麼? – Grambot

回答

6

當您輸出到文件時,stdio庫會自動阻塞出站位。

當某個程序調用exit(2)或從main(),返回時,任何剩餘的緩衝位都將被刷新。

在這樣不會產生太大的輸出方案,的I/O時的目的地不是一個tty從main(),迴歸之後會出現的所有。這通常會自行改變I/O操作的模式和順序。

在這種情況下,結果是由fork()系列調用進一步複雜。這將複製每個子圖像中的部分填充和尚未刷新的I/O緩衝區。

在程序調用fork(),之前,可能會先使用fflush(3)來刷新I/O。如果未執行此刷新,則可能需要除了一個(通常是子項)以外的所有進程到_exit(2)而不是exit(3)或從main(),返回,以防止相同的位輸出超過一次。 (_exit(2)少了點exit系統調用)。

+0

我可以在哪裏找到更多關於你解釋事情的詳細信息。提前致謝。 – akmal

+1

'man 2 _exit;男人2叉;男子3出口;男人3 stdio; man 3 fflush',也許http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html – DigitalRoss

4

fork()if塊在你的程序中執行兩次,因爲一旦叉是成功的,該程序是由兩個過程(孩子控制父進程).So fork()if塊內,由子進程和父進程執行。所以它會有不同的輸出比預期,因爲它是由兩個不同的過程控制,他們的執行的命令未知。即。無論是孩子還是父母都可以先執行後fork()

對於輸出和文件之間的行爲差​​異。這是原因。

您寫入緩衝區的內容(最終寫入file(disk))不保證寫入文件(磁盤)immediatley。只有在執行main()完成後,它才大部分刷新到磁盤。而輸出到終端,執行期間main()

在將數據寫入磁盤文件之前,kernel實際上將數據複製到緩衝區,稍後在後臺,內核收集所有髒緩衝區,將其優化排序並將其寫入文件(磁盤)。被稱爲回寫。它還允許內核延遲寫入更多空閒期間和許多一起寫

爲了避免這樣的行爲,這是一件好事使用fork()

int pid; 
if((pid = fork()) == -1) 
{ //fork unsuccessful 
} 
else if (pid > 0) 
{ //This is parent 
} 
else 
{//This is child 
} 
+0

你能否澄清一下'fork'裏面'if'執行兩次。我認爲child不會執行'fork'它會收到'fork'的結果,並且在'fork'之後的第一條語句中開始執行。 – akmal

2

緩衝流有時會產生一些奇怪的結果有程序三種不同的條件檢查...特別是當你有使用相同的多個進程緩衝流。動力的緩衝液是flushed,你會看到不同的結果:

int main() 
{ 
    int i; 
    FILE * fd = fopen(yourfile, "w"); 
    for(i = 0; i < 5; i++) 
    { 
     fprintf(fd, "%d", i); 
     fflush(fd); 
     if((i%2)==0) 
     if(fork()) 
      fork(); 
    } 
} 

此外,爲您調試的目的,它可能是不錯的轉儲進程的ID,這樣你可以看到哪個進程產卵其中,並有更好地瞭解正在發生的事情。 getpid()可以幫助你。

1

爲什麼我在 分叉時在終端和文件之間有不同的輸出?

C標準庫函數使用內部緩衝加快速度。大多數實現將完全緩衝的IO用於文件流,行緩衝用於標準輸入/標準輸出和無緩衝用於標準錯誤。叉前

  1. 使用明確的緩衝區刷新通過fflush(3)
  2. 設置緩衝區通過setvbuf(3)
  3. 使用write(2),而不是STDLIB的printf(3)
  4. 手動鍵入:

    所以你的問題可以用許多方式解決輸出到stderr默認通過fprintf(3)*

  5. 在派生的進程,而不是
  6. 退出與_exit(2)**

最後兩位可能無法按預期工作,如果:
*您實現不使用默認的無緩衝寫至標準錯誤(這是由ISO要求C)
**您已經在孩子中寫入了超過默認緩衝區大小,並且是否自動刷新。

PS。再次,如果您需要更深入的標準庫函數和緩衝知識,我推薦閱讀Advanced Programming in the UNIX Environment (2nd Edition) by W. Richard Stevens and Stephen A. Rago

PPS。順便說一句,你的問題是一個非常受歡迎的C/C++程序員職位面試問題。

相關問題