天天看點

Linux檔案共享(一)——程序與打開檔案

linux支援在不同程序間共享打開檔案。為了說明檔案共享,先來說明核心用于所有i/o的資料結構。 他們之間的關系決定了在檔案共享方面一個程序對另一個程序可能産生的影響。

(1) inode(i節點): 儲存一個檔案的通用資訊,每個inode有一個inode number,在檔案系統中,一個inode number能夠唯一地辨別一個檔案。

(2) dentry(目錄項對象):每個dentry代表路徑中的一個特定部分。儲存一個目錄的連結資訊。個人了解:描述一個檔案和一個名字的對應關系。

(3) file(檔案對象):儲存一個打開的檔案與一個程序的關系,檔案對象表示程序已經打開的檔案 在記憶體中的表示,該對象不是實體上的檔案。它是由相應的open()系統調用建立,由close()系統調用銷毀(隻有其引用計數為0時才銷毀)。多個程序可以打開和操作同一個檔案,是以同一個檔案也可能存在多個對應的檔案對象。 它即為apue中所說的“目錄表項”,内涵檔案偏移等資訊。

(1)  files_struct:每個程序用一個files_struct結構來記錄檔案描述符的使用情況,這個結構稱為使用者打開檔案表(含有描述符表)。它是程序的私有資料。它即為apue中的“打開檔案描述符表”。

(2) fs_struct:fs_struct 結構描述程序與檔案系統的關系。

這些對象的關系如下圖所示。

Linux檔案共享(一)——程式與打開檔案

再來看一下apue中描述的關于檔案和程序的關系,如下圖( 圖3-1)顯示了程序的三張表之間的關系。該程序有兩個不同的打開檔案—一個檔案打開為标準輸入(檔案表述符0),另一個打開為标準輸出(檔案描述符1)。

Linux檔案共享(一)——程式與打開檔案

(1)每個程序在程序表中都有一個記錄項(打開檔案描述符表),記錄項中包含有一張打開檔案的描述符表,可将其視為一個矢量,每個描述符占用一項。

   每個檔案描述符相關連的是:

·       檔案描述符标志(close_on_exec)。

·       指向一個檔案表項的指針。

注解:這裡描述的即為linux程序描述符(tast_struct)中的files(files_struct類型)。

(2)核心為所有打開檔案維持一張檔案表。每個檔案表項包含:

·        檔案狀态标志(包含讀寫,填寫,同步,非阻塞等)

·        目前檔案偏移量

·        指向該檔案v節點表項的指針。

注解:這裡描述的“檔案表項”即為linux系統下的檔案對象(file)。

(3)每個打開的檔案都有一個v節點結構。v節點包含了檔案類型和對此檔案進行各種操作的函數的指針。對于大多數檔案,v節點還包括了該檔案的i節點。這些資訊是再打開檔案時從磁盤上讀入記憶體的。這些檔案都是從磁盤讀入記憶體的,是以可以快速使用這些參數。

注解:這裡描述的v節點,在linux中即為i節點,對應inode對象。

之後我們的讨論也主要圍繞這三大對象。      

在我們讨論的幾個和檔案有關的對象中都存在引用計數,而他們的含義各不相同,了解這些引用計數對我們下面的讨論至關重要。

(1) file_struct引用計數:表明共享此結構的程序(線程)數。(我們讨論線程共享檔案會用到)

(2) fs_struct引用計數:表明共享此結構的程序(線程)數。(我們讨論線程共享檔案會用到)

(3) file對象引用計數:打開檔案引用計數,引用這個file對象描述符數。(dup和fork都會增加這個計數,第一次open會使此計數為1,close會減小此計數,為0時銷毀file對象)

(4) dentry引用計數:每一個計數對應一個file對象。

(5) inode引用計數:每一個計數對應一個dentry。

擴充:

(1)close_on_exec标志

從圖中可見,這個标着在程序的files_struct中, 是一個程序所有檔案描述符(檔案句柄)的位圖示志,每個比特位對應一個打開的檔案描述符,用于确定在調用系統調用execve()時需要關閉的檔案描述符,可用fcntl設定。

(2)附錄:i節點結構

struct dinode

{

 ushort di_mode;  /*檔案類型+使用者權限*/

 short di_nlink;  /*檔案連結數*/

 ushort di_uid;  /*屬主使用者id*/

 ushort di_gid;  /*屬主使用者組id*/

 off_t di_size;  /*檔案大小*/

 char di_addr[40]; /*檔案資料區起點位址*/

 time_t di_atime; /*最後通路時間*/

 time_t di_mtime; /*最後修改時間*/

 time_t di_ctime; /*建立時間*/

};

繼續閱讀