229
技術社區[雲棲]
Linux文件共享(二)——兩個獨立進程打開同一個文件
如果兩個獨立進程各自打開了同一文件,則有圖3-2中所示的安排。我們假定第一個進程使該文件在文件描述符3上打開,而另一個進程則使此文件在文件描述符4上打開。打開此文件的每一個進程都得到一個文件對象,但對一個給定的文件隻有一個v節點表項。每個進程都有自己的文件對象的一個理由:這種安排使每個進程都有它自己對該文件的當前位移量。這種情況不會增加對應的打開文件引用計數,而會增加dentry的引用。
給出了這些數據結構後,現在對前麵所述的操作作進一步說明。
(1) 在完成每一個write後,在文件表項中的當前文件位移量即增加所寫的字節數。如果這使當前文件位移量超過了當前文件長度,則在i節點表象中的當前文件長度被設置為當前文件位移量(也就是該文件加長了)。
(2) 如果用O_APPEND標誌打開一個文件,則相應標誌也被設置到文件表項(file對象)的文件狀態標誌中。每次對這種具有填寫標誌的文件執行寫操作時,在文件表項中的當前文件位移量首先被設置為i節點表項中的文件長度。這就使得每次寫的數據都添加到文件的當前尾端處。
(3) lseek值修改文件表項中的當前文件位移量,沒有進行任何I/O操作。(不影響i節點,隻影響file對象,詳細分析請見lvyilong316博客:空洞文件)
(4) 若一個文件用lseek被定位到文件當前的尾端,則文件表項中的當前文件位移量被設置為i節點表項中的當前文件長度。
將圖3-2轉化為linux下的具體實現,如下圖所示。
注:綠色部分為進程1的私有資源,黃色部分為進程2的私有資源,藍色部分為進程1、進程2的共享資源。
擴展:
(1)用leek定位到當前文件尾端,在向文件寫入(write)與使用O_APPEND打開(open)文件再寫入(write)的區別:
前者是“非原子”操作,假如兩個進程都使用前者的方式向文件結尾寫入數據,那麼有可能產生這樣的調度序列:
進程A:leek 進程B:leek 進程A:write 進程B:write
第一個進程寫入後,文件(i節點)的偏移已經改變,第二個進程再寫會覆蓋第一個進程剛寫的內容。而是用O_APPEND的open,會使內核每次對文件寫之前,都將進程的當前偏移量(file對象中的)設置到文件的尾端處(i節點的當前文件長度)。
注意:對於多個進程打開同一文件的情況,每個進程都有它自己的文件表項(file對象),其中有它自己的文件位移量,所以對於多個進程讀同一文件都能正確工作。但是,當多個進程寫同一文件時,則可能產生預期不到的結果。(可以使用pread,pwrite)。
總結:兩個獨立進程打開同一文件,對應不同的file對象,每個進程調用close隻影響本進程的“打開文件計數”(file對象的引用計數)。
最後更新:2017-04-03 12:56:03