2017-07-06 41 views
1

fork(2)我運行在Linux系統上的手冊頁說以下內容:爲什麼父進程的標準輸入在關閉分叉子進程的標準輸入文件描述符後仍然接受輸入?

The child inherits copies of the parent's set of open file descriptors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent. This means that the two file descriptors share open file status flags, file offset, and signal-driven I/O attributes (see the description of F_SETOWN and F_SET‐SIG in fcntl(2)).

和Python文檔中提到

_exit() should normally only be used in the child process after a fork() .

當然,_exit不會調用清理處理程序,問題是, ,如果你看這個代碼,例如:

newpid = os.fork() 
if newpid == 0: 
    os.close(0) 
else: 
    time.sleep(.25) 
    input() 

父進程仍然接受輸入儘管事實上子進程關閉了標準輸入,但來自stdin。那好,下面的代碼逆轉:

newpid = os.fork() 
if newpid == 0: 
    input() 
else: 
    time.sleep(.25) 
    os.close(0) 

現在,它的對面,這個時候,關閉標準輸入不是孩子的父進程。這在子進程中調用input()調用EOFError

這看起來像[child]進程寫入/修改父級的文件描述符時,它不會影響[parent]。也就是說,子進程獲取較新的文件描述。

那麼爲什麼打電話_exit作爲Python文檔狀態來防止調用清理處理程序,如果由子進程執行的操作不影響父進程?讓我們來看看_EXIT(2)手冊頁:

The function _exit() terminates the calling process "immediately". Any open file descriptors belonging to the process are closed; any children of the process are inherited by process 1, init, and the process's parent is sent a SIGCHLD` signal.

The function _exit() is like exit(3) , but does not call any functions registered with atexit(3) or on_exit(3). Open stdio(3) streams are not flushed. On the other hand, _exit() does close open file descriptors, and this may cause an unknown delay, waiting for pending output to finish.

fork()手冊中沒有提到的是,子進程的清理處理繼承自父。這對父母有什麼影響?換句話說,爲什麼不讓孩子過程自己清理,爲什麼不呢?

+1

'EOFError'不是由'os.close(0)'造成的。即使你使用'time.sleep(5)',你也可以立即得到它。 – Barmar

+1

如果stdin被重定向到管道或文件,它也不會發生。 – Barmar

回答

1

我假設你從終端內的shell運行這個。

shell在新進程組中啓動Python進程,並使用tcsetpgrp()將其設置爲TTY上的前臺進程組。

一旦父Python進程終止,shell收回終端的控制權(它將自己設置爲前臺進程組)。 shell不知道Python中的分叉子仍在運行。

當不屬於前臺進程組的進程嘗試從終端讀取時,它通常會收到一個SIGTTIN信號。但是,在這種情況下,進程組因爲其領導已終止而被孤立,因此子進程在TTY上從read()獲得EIO錯誤。 Python將其視爲EOFError

+0

錯誤發生在pareent進程終止之前。放置更長的'time.sleep',你會在父親退出前立即看到'EOFError'。 – Barmar

+0

此外,如果將其更改爲'print(input())',則會在報告錯誤之後成功讀取輸入。 – Barmar

+0

@Barmar這不是我在Linux機器上觀察到的行爲。 – ephemient

相關問題