2014-11-01 158 views
1

我想了解三個流的行爲 - stdout,stdinstderr。我無法從任何教科書中得到答案,所以我來到了這裏。stdin,stdout和stderr在?之間共享?

我知道這三個存儲在文件描述符表中,文件描述符爲0(標準輸入),1(標準輸出)和2(標準錯誤)。我也知道這些不僅僅是文件描述符,而是可以被重定向的I/O流。好的,那麼分享怎麼樣?

考慮三種情況:

  1. 當叉子()被調用:子進程和父進程共享文件描述符,但它們具有相同的標準輸入,輸出和錯誤?
  2. 當一個線程被創建時:線程共享文件描述符,但I/O流?
  3. 當execl()被調用時:在這種情況下,當前過程映像被新的過程映像覆蓋。如果我這樣做execl("./a.out", "a.out", NULL);,那麼這個新的可執行文件會得到stdin,stderr和stdout的全新拷貝嗎?

明智的答案是值得歡迎的。

回答

2

爲了瞭解發生了什麼,請考慮這些是跨越流程邊界的溝通渠道。我會避免將它們稱爲流,因爲它們在不同的環境中使用,但它們是相關的。

現在,首先,filedescriptor只是表示這些通道的進程特定表的索引,它們基本上是一種不透明的句柄。但是,下面是第一個答案:由於線程是進程的一部分,因此它們也共享這些描述符,所以如果從兩個線程寫入同一個通道,它將通過相同的通道,因此在進程之外,兩個線程難以區分。

然後,當fork()被調用時,進程被有效地複製。這是通過寫入時複製優化來完成的,但這仍然意味着它們也具有代表這些通信通道的不同表格。一個進程中索引爲2的條目與fork中索引爲2的條目不同。對於進程內的任何結構,如果您創建了C FILE*或C++ std::stream,那麼它也會與其他數據一起被複制。

當調用execl()時,進程仍然「擁有」某些通道到外部。這些從管理進程的操作系統分配給它。這意味着指數2仍然可以用於與外界溝通。在啓動時,運行時庫然後將創建例如FILE *用於C中三個衆所周知的頻道stdin,stdout和stderr。

問題仍然存在,當一個進程分流到外部渠道時會發生什麼。在這裏,答案很簡單,不管是關閉還是繼承,都可以在每個頻道的基礎上進行配置。如果它是繼承的,它仍然可以在子進程中使用。任何寫入繼承通道的內容都會在父進程的輸出結束時結束。

關於分叉過程的標準輸入,實際上,我不知道,我覺得輸入默認那些被關閉的一個,因爲輸入發送到多個目標沒有意義。另外,我從來沒有發現需要實際處理來自子進程中的標準輸入的輸入,除非該輸入是父進程特別提供的(類似於shell中的管道,儘管那些是兄弟而不是父和子)。

注:我不知道,如果這個描述很清楚,請不要猶豫,問我會盡量完善事物的理解。

+0

謝謝你的精心答覆。我發現它有點難以接受。據我瞭解,對於情況2和3,stdin,stdout和stderr是共享的。我無法理解fork()的情況。 你在說如果一個文件被父進程打開,並且被子進程再次打開;這兩個文件描述符是獨立的? – 0aslam0 2014-11-02 06:31:32

+0

也請在這裏檢查。 http://stackoverflow.com/questions/26696811/making-stdin-writable-in-a-safe-and-portable-way – 0aslam0 2014-11-02 07:45:14

+0

是的,在情況2個3的標準流被共享,線程總是共享進程和EXECL ()不會更改進程(它只會更改進程運行的內容)。在fork()的情況下,繼承的流仍然可用於子進程。在這種情況下,數據從父進程和子進程都流向哪個進程接收數據。 – 2014-11-04 20:51:10

0

讓我們假設相反。

如果他們沒有共享相同的位置(這基本上是一個文件描述符),那麼這些場景將不得不想出一些東西?那是可能的 - 人們可以從確定性的機器得出結論,事實並非如此。

這就是答案。是的,他們共享相同的位置。

+0

很好。這也是我的結論。但是當我試圖運行一個小代碼來檢查它時,我遇到了意想不到的錯誤。我應該用我的問題補充還是發佈一個新問題? – 0aslam0 2014-11-01 08:56:32

+0

@ xachu4u - 那是你的選擇 – 2014-11-01 08:57:22