總結下linux下的IPC使用原理及注意事項
阿新 • • 發佈:2019-01-25
首先說明一下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)
{
printf("lseek error\n");
return -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(改變檔案大小)進行設定大小。
樣子後面對映後才可使用,否過會越界使用而出現宕機
high memory |-------| A
| |
| |
| | memory mapped partion of file
| |
| |
low memory |-------| B
file mapped |-----------------|
|offfset| len |
|-----------------|
A' B'
以上fd[A--B]對映到[A'--B']範圍內,操作[A-B]與操作下面file mapped一樣
C、copy_to_user與mmap的工作原理
copy_to_user
在每次拷貝時需要檢測指標的合法性,也就是使用者空間的指標所指向的地址的確是一段
該程序本身的地址,而不是指向了不屬於它的地方,而且每次都會拷貝一次資料,頻繁
訪問記憶體,由於虛擬地址連續,實體地址不一定會連續,從而造成CPU的CACHE頻繁失效,
從而使速度降低
mmap優點:
僅在第一次使用時為程序建立頁表,也就是將一段實體地址對映到一段虛擬地址上,以後
操作時不再檢測其地址的合法性(合法性交由CPU頁保護異常來做),另一方面是核心下
直接操作mmap地址,可以不用頻繁拷貝,也就是說在核心下直接可用指標向該地址操作,
而不再在核心中專門開一個緩衝區,然後將緩衝區中的資料拷貝一次進來,mmap一般是
將一段連續的實體地址對映成一段虛擬地址,當然,也可以將每段連續,但各段不連續
的實體地址對映成一段連續的虛擬地址,無論如何,其實體地址在每段之中是連續的,
這樣一來,就不會造成CPU的CACHE頻繁失效,從而大大節約時間
總結:
mmap 地址影射 包括
A、記憶體實體地址 -- 虛擬地址
B、檔案裝置--虛擬地址
目的是通過 虛擬地址訪問 目標地址 ,目標地址 包括 實體地址 檔案裝置等