首先說明一下mmap函式用途:
採用共享記憶體通訊的乙個顯而易見的好處是效率高,因為程序可以直接讀寫記憶體,而不需
要任何資料的拷貝
1、將乙個普通檔案對映到記憶體中,通常在需要對檔案進行頻繁讀寫時使用,這樣用記憶體讀
寫取代i/o讀寫,以獲得較高的效能;
2、將特殊檔案進行匿名記憶體對映,可以為關聯程序提供共享記憶體空間;
適用於具有親緣關係的程序之間。由於父子程序特殊的親緣關係,在父程序中先呼叫mmap
(),然後呼叫 fork()。那麼在呼叫fork()
之後,子程序繼承父程序匿名對映後的位址空間,同樣也繼承mmap()
返回的位址,這樣,父子程序就可以通過對映區域進行通訊了。
3、為無關聯的程序提供共享記憶體空間,一般也是將乙個普通檔案對映到記憶體中。
普通檔案fd用於mmap引數:
1、最終被對映檔案的內容的長度不會超過檔案本身的初始大小,即對映不能改變檔案的大小
2、記憶體的保護是以頁為基本單位的,即使被對映檔案只有乙個位元組大小,核心也會為對映分
配乙個頁面大小的記憶體,用於程序間通訊的有效位址空間大小不會超過檔案大小及乙個頁
面大小的和
3、檔案一旦被對映後,呼叫mmap()的程序對返回位址的訪問是對某一記憶體區域的訪問,暫時
脫離了磁碟上檔案的影響,只有在呼叫了munmap()後或者msync()時,才把記憶體中的相應
內容寫回磁碟檔案,所寫內容仍然不能超過檔案的大小。
a、ftok使用說明
key_t ftok( char * fname, int id ) fname就時你指定的檔名,id是子序號。
在一般的unix實現中,是將檔案的索引節點號取出,前面加上子序號得到key_t的返回值。
如指定檔案的索引節點號為65538,換算成16進製為0x010002,而你指定的id值為38,換
算成16進製為0x26,則最後的key_t返回值為0x26010002。
當刪除重建檔案後,索引節點號由作業系統根據當時檔案系統的使用情況分配,因此與原來
不同,所以得到的索引節點號也不同。
如果要確保key_t值不變,要目確保ftok的檔案不被刪除,要麼不用ftok,指定乙個固定的key_t值
注意:ftok將乙個已存在的路徑名和乙個整數識別符號轉換成乙個key_t值。
ftok會組合三個值來產生key:
1、pathname所在的檔案系統的資訊。
2、該檔案在本檔案系統內的索引節點號。
3、id的低序8位。
key_t
的生成是以乙個已存在的檔案作為輸入,並不是簡單的字串雜湊函式,必須真正存在某
個檔案,才能將其位置傳入ftok。
b、檔案空洞是怎麼回事
off_t lseek(int filedes, off_t offset, int whence);
引數 offset 的含義取決於引數 whence:
當前檔案偏移量(current file offset),以下簡稱為 cfo,非負整數
1. 如果 whence 是 seek_set,檔案偏移量將被設定為 offset。
2. 如果 whence 是 seek_cur,檔案偏移量將被設定為 cfo 加上 offset,
offset 可以為正也可以為負。
3. 如果 whence 是 seek_end,檔案偏移量將被設定為檔案長度加上 offset,
offset 可以為正也可以為負。
注意: 對於普通檔案(regular file),cfo 是乙個非負整數。但對於特殊裝置,cfo
有可能是負數。因此,我們不能簡單地測試 lseek 的返回值是否小於 0 來判斷 lseek
成功與否,而應該測試 lseek 的返回值是否等於 -1 來判斷 lseek 成功與否。
if (lseek(fd, 16384, seek_set) == -1)
測試結果表明,lseek並不能extend檔案大小,需要write一下0的資料
/*** 參看前面man手冊中的說明,mmap()不能用於擴充套件檔案長度。所以這裡必須事
* 先擴大目標檔案長度,準備乙個空架子等待後面讀寫使用:
* 如果 offset 比檔案的當前長度更大,下乙個寫操作就會把檔案「撐大(extend)」。
* 這就是所謂的在檔案裡創造「空洞(hole)」。沒有被實際寫入檔案的所有位元組
* 由重複的 0 表示。空洞是否占用硬碟空間是由檔案系統(file system)決定的
*/ int tmpdata = 0x00;
lseek(fd,maxsize-4,seek_set);
write(fd,(const void*)&tmpdata,sizeof(ui32)); /* 寫入乙個int型資料長度 */
或者write(fd, "\0", 1); /* 在檔案最後新增乙個空字元 */
也可以使用ftruncate(改變檔案大小)進行設定大小。
即對於普通檔案的對映前,首稱必須將fd的檔案擴充套件到與你所對映空間的同樣大小,這
樣子後面對映後才可使用,否過會越界使用而出現宕機
high memory |-------| a
| |
| |
| |
| |
low memory |-------| b
|offfset| len |
|-----------------|
a' b'
c、copy_to_user與mmap的工作原理
copy_to_user
在每次拷貝時需要檢測指標的合法性,也就是使用者空間的指標所指向的位址的確是一段
該程序本身的位址,而不是指向了不屬於它的地方,而且每次都會拷貝一次資料,頻繁
訪問記憶體,由於虛擬位址連續,實體地址不一定會連續,從而造成cpu的cache頻繁失效,
從而使速度降低
mmap優點:
僅在第一次使用時為程序建立頁表,也就是將一段物理位址對映到一段虛擬位址上,以後
操作時不再檢測其位址的合法性(合法**由cpu頁保護異常來做),另一方面是核心下
直接操作mmap位址,可以不用頻繁拷貝,也就是說在核心下直接可用指標向該位址操作,
而不再在核心中專門開乙個緩衝區,然後將緩衝區中的資料拷貝一次進來,mmap一般是
將一段連續的物理位址對映成一段虛擬位址,當然,也可以將每段連續,但各段不連續
的物理位址對映成一段連續的虛擬位址,無論如何,其實體地址在每段之中是連續的,
這樣一來,就不會造成cpu的cache頻繁失效,從而大大節約時間
總結:mmap 位址影射 包括
a、記憶體實體地址 -- 虛擬位址
b、檔案裝置--虛擬位址
目的是通過 虛擬位址訪問 目標位址 ,目標位址 包括 實體地址 檔案裝置等
Linux下的IPC 命名管道的使用
程序之間通過管道來進行通訊是一種常用的方法,顧名思義,管道就是一端進 寫 一端出 讀 的fifo佇列,這個佇列由核心管理,有一定大小 一般是4k 有文章上提到,如果需要修改該快取區,需要重新編譯核心 修改linux limits.h裡pipe buf的定義 需要明確的是,雖然管道在理論上是雙向的,但...
linux檔案操作總結(下)
建立目錄 include include int mkdir const char path,mode t mode 目錄路徑 目錄許可權 若執行成功則返回0,失敗則返回 1,錯誤 存入errno刪除目錄 include include int mkdir const char path,mode ...
Linux 下的IPC控制命令
shell環境控制ipc ipc物件一經建立,系統核心即會為該物件分配相關資料結構。為了方便對ipc物件的管理,linux系統提供了專門的ipc控制命令,主要包括檢視ipc物件資訊的ipcs和刪除ipc物件的ipcrm。1 檢視ipc物件資訊 ipcs 引數 1 引數說明 a 檢視全部ipc物件資訊...