閱讀229 返回首頁    go 技術社區[雲棲]


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的共享資源。

擴展

1leek定位到當前文件尾端,在向文件寫入(write)與使用O_APPEND打開(open)文件再寫入(write)的區別:

前者是“非原子”操作,假如兩個進程都使用前者的方式向文件結尾寫入數據,那麼有可能產生這樣的調度序列:

進程Aleek  進程Bleek 進程Awrite 進程Bwrite

第一個進程寫入後,文件(i節點)的偏移已經改變,第二個進程再寫會覆蓋第一個進程剛寫的內容。而是用O_APPENDopen,會使內核每次對文件寫之前,都將進程的當前偏移量(file對象中的)設置到文件的尾端處(i節點的當前文件長度)。

 

注意對於多個進程打開同一文件的情況,每個進程都有它自己的文件表項file對象),其中有它自己的文件位移量,所以對於多個進程讀同一文件都能正確工作。但是,當多個進程寫同一文件時,則可能產生預期不到的結果。(可以使用preadpwrite)。

總結:兩個獨立進程打開同一文件,對應不同的file對象,每個進程調用close隻影響本進程的“打開文件計數”(file對象的引用計數)。

最後更新:2017-04-03 12:56:03

  上一篇:go C# 係統應用之通過注冊表獲取USB使用記錄(一)
  下一篇:go 有關軟件工程