用fork 建立乙個新程序。當它們併發(即同時)寫入檔案時,會發生什麼?

時間 2021-06-05 19:29:58

1樓:錢子晨

fork的乙個特性就是父程序的所有開啟檔案描述符都被複製到子程序中。我們說「複製」是因為對每個檔案描述符來說,就好像執行了dup函式。父程序和子程序每個相同的開啟描述符共享乙個檔案表項(見下圖i)。

考慮下述情況,乙個程序具有3個不同的開啟檔案,它們是標準輸入、標準輸出和標準錯誤。在從fork返回時,我們有了如圖ii中所示的結構。

重要的一點是,父程序和子程序共享同乙個檔案偏移量。考慮下述情況:乙個程序fork了乙個子程序,然後等待子程序終止。

假定,作為普通處理的一部分,父程序和子程序都向標準輸出進行寫操作。如果父程序的標準輸出已重定向(很可能是由shell實現的),那麼子程序寫到該標準輸出時,它將更新與父程序共享的該檔案的偏移量,在這個例子中,當父程序等待子程序時,子程序寫到標準輸出:而在子程序終止後,父程序也寫到標準輸出上,並且知道其輸出會追加在子程序所寫資料之後。

如果父程序和子程序不共享同一檔案偏移量,要實現這種形式的互動就要困難得多,可能需要父程序顯式地動作。

父子程序間共享開啟檔案,即父子程序寫同一描述符指向的檔案,這是一種很有用的應用場景。例如,假如父子程序同時寫入一檔案,共享檔案偏移量會確保二者不會覆蓋彼此的輸出內容。不過,這並不能阻止父子程序的輸出隨意混雜在一起(假定所用的描述符是在fork之前開啟的,見圖ii),一般地,這並不符合我們的預期。

要想規避這一現象,需要進行程序間同步。比如,父程序可以使用系統呼叫wait來暫停執行並等待子程序退出。shell就是這麼實現的:

只有當執行命令的子程序退出後,shell才會列印出提示符(除非使用者在命令列最後加上&符以顯式在後台執行命令)。

在fork之後處理檔案描述符有以下幾種常見的情況。

如果不需要這種對檔案描述符的共享方式,那麼在設計應用程式應該有如下考慮。

父程序等待子程序完成。在這種情況下,父程序無需對其描述符做任何處理。當子程序終止後,它曾進行過讀、寫操作的任一共享描述符的檔案偏移量已做了相應更新。

令父、子程序使用不同的檔案描述符,並各自立即關閉不再使用的描述符(亦即那些經由其他程序使用的描述符),如圖iii。這樣就不會干擾對方使用的檔案描述符。如果程序之一執行了exec,那麼執行時關閉功能(close-on-exec)也會很有用處。

這種方法是網路服務程序經常使用的。

i. Kernel data structures after dup

ii. Sharing of open files between parent and child after fork

iii. Duplication of file descriptors during fork(), and closing of unused descriptors

2樓:

如果是一般的檔案,write是原子的,先到先得。併發寫會被檔案物件的mutex序列化,也就是資料會先後寫入:

ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count)

ret = vfs_write(f.file, buf, count, ppos);

if (ret >= 0 && ppos)

f.file->f_pos = pos;

fdput_pos(f);

} return ret;

}這裡的fdget_pos和fdput_pos會lock/unlock struct file的f_pos_lock :

unsigned long __fdget_pos(unsigned int fd)

其中FMODE_ATOMIC_POS這個標誌是給REG / DIR的檔案準備的:

/* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */

if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))

f->f_mode |= FMODE_ATOMIC_POS;

特殊檔案比如字元裝置檔案的write是不經過這個鎖的,所以併發的write行為是由檔案系統的實現決定的。

3樓:劉雲賓

這個問題直接寫個程式測試就行了,結果是不確定的,資料肯定都存在,不會覆蓋,因為他們共享同乙個檔案表項,但順序不一定,

以下是測試程式:

#include

#include

#include

#include

#include

int main() else

為什麼乙個程序對共享記憶體的寫入另乙個程序可以立即可見?不考慮cpu的cacheline嗎?

張驍 這事的根本在MMU上,實體地址與邏輯位址的對映實現的。簡化思維,你我分別是兩個不同的程序,住在兩間不同的屋子裡,房間裡有一面分隔成很多小方塊的玻璃牆,這面玻璃牆就是專屬於我們各自的記憶體 邏輯記憶體 而實際上,這些個小方塊都是通過複雜而巧妙的機構對映到遠方的一大塊黑板上 物理記憶體 我們看到的...

Android可以徹底殺死乙個程序嗎?

kjkj 安卓軟體可以通過JNI來fork乙個自己的子程序,用來不斷監聽自己的主程序 即應用本身 一旦監聽到自己的主程序被殺死,子程序就可以幹很多事情了 什麼重新啟動自己的應用程式 啟動自己的服務.就算應用本身被解除安裝,該應用的子程序還會繼續存在,繼續執行。因此子程序很難殺死,其實連找到他都很難,...

可以多個server程序同時監聽乙個unix socket檔案麼?

這個和port reuse 沒有關係。先listen後,server會建立乙個socket描述符,fork之後,子程序的描述符和父程序的一致,所以子程序accept會和父程序取相同的佇列中的connet任務。 特立獨行的豬 猛的一看竟然是兩年前的問題了,看了各位義憤填膺的回答,簡單發表下自己的看法,...