<轉>APUE:mmap函數,apuemmap函數

來源:互聯網
上載者:User

<轉>APUE:mmap函數,apuemmap函數
起初

看過一遍記憶體對應 I/O,意思大概是懂了,就是直接操作檔案再而直接通過緩衝區來操作,減少一些read、write調用所花費的時間。加上文中給出一個copy的例子,意思也好理解的。
不過困擾的來了,我琢磨著在映射兩個檔案後,再使用memcpy記憶體複製函數將檔案寫入完全可以,但是這是兩個檔案的操作,我想一個檔案自己對自己的修改呢?只有一個檔案的時候,該怎麼做呢?於是自己就開始構建一個程式來驗證一下。正好也順手將書後的習題14.11也解決掉:)

猜想

首先設想建立一個空檔案,先寫入一點資料,接著映射到緩衝區區,接著再寫一點資料進去。簡單說就是open==> write ==> mmap ==> write 但是一想這邊根本沒有涉及到使用緩衝區,還是建立在檔案的操作上,失敗!

繼續想一個思路,書上有一句話 此函數的返回地址是該映射區的返回地址 ,意思就是說mmap的傳回值可以拿過來用,我們可以將它的內容輸出,我個人猜想這個內容應該就是檔案的內容。那麼這樣我不就可以對這個傳回值進行相應的操作,這不就是在對映射的緩衝區進行操作嗎?

鑒於書中提到一個函數msync是將映射區的修改同步到檔案中,那麼對檔案的修改也就能體現出來了。一氣呵成的想法,最後還有一個釋放映射區,這是一個基本的清理操作。大體上應該可以設計了。

思路整理下,首先是建立檔案,寫入一點資料,然後映射過去,讀映射區的內容(傳回值) 修改映射區,同步寫入檔案,清理工作。這個思路應該差不多了。

實現

編碼之前的一個問題,mmap的傳回值是void *, 而我們要展示的確是字串之類的,於是想到得強制轉換下這個傳回值。這一步解決後,開始編碼

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<fcntl.h>#include<unistd.h>#include<sys/mman.h>#include<errno.h>static void error(const char *msg){    fprintf(stderr,"%s:%s\n",msg,strerror(errno));    exit(1);}int main(void){    int     fd;    char     *dst;    if((fd = open("mapfile",O_RDWR|O_CREAT|O_TRUNC,0666)) < 0)        error("open error");    if(write(fd,"abc",3) != 3)        error("wirte error");    /*let this file map to memory area*/    if((dst =(char *)mmap(0,64,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED)    error("mmap error");    close(fd);    printf("%s\n",dst);    dst[2]='d';    printf("%s\n",dst);    if(msync((void *)dst,64,MS_SYNC) < 0)        error("msync error");    if(munmap((void *)dst,64) < 0)        error("munmap error");    return 0;    }

 

初期的一個編碼大概是這樣的,運行後的結果還是比較不錯的.

細究下這個代碼,我嘗試的是去改已經寫入的內容,這個確實有一個修改的意思了,看來對傳回值的猜想是正確的,對傳回值的修改就是對這個映射區的修改。同時,我也測試了將檔案描述符關閉後,緩衝區是不受影響的,照樣可以操作,並且是能夠同步到檔案中的。這點確實很關鍵。

可我並不覺著這樣就可以了,我的目的是繼續往裡面寫資料,就像一開始想的那樣,在映射後我還需要將其他資料寫入, 看看這個是否是和write函數一樣可以做到這一點。

修改代碼

我們一開始只是寫入了3個,而給的緩衝區是64的,足夠再寫入的。但是啟動並執行結果

和上面的一樣,沒有任何的改變。。。 按照道理來時應該會有一個x出現的。

看書,發現書上的copy函數的例子中,有一個位移的設定,書中也有個說法對應檔的啟示位移量受系統虛存頁的限制,如果映射區的長度不是頁的整數倍,任何的變動,都不會再檔案中反映出來,不能用mmap將資料添加到檔案中,需要加長該檔案 也就是說我這邊需要一個位移,看書上的copy的例子,上面是從檔案開始位移了inputfile的長度。也就是說現在這個檔案從開始到位移的位置有一個空洞,那麼再映射過去後,顯示的量應該就是能滿足了,這樣就可以將所更改的寫入到檔案中。回到我剛才的那個,雖然映射區是給64,但是檔案的長度不足,這和write不一樣,write可以直接接著後面寫。所以必須檔案的大小要滿足才行。

繼續修改代碼

此刻啟動並執行結果就符合我的猜想了,下面是結果的運行

可以看到,cat輸出了我剛剛插入的一個'x',繼而看檔案的真實情況,也完全符合我的猜想,在第十一位放入了一個x,至於為什麼輸出的還是三個,因為字串的結尾有一個'\0'則'x'沒有連在一起。

其實還有一個細節,再形成檔案空洞的時候,不僅僅是要位移位置,還需要寫入一個字元,來標識這個檔案真實長度,否則結果和不使用位移一樣檔案的長度還是原來的大小,並沒有被擴充。

有一個不錯的方法使用ftruncate,直接設定檔案的大小,省卻使用lseek和write的繁雜。

總結

mmap再IPC中提及到,但是在APUE中涉及了這個,這讓我想起了再做網路攝影機驅動的時候,使用過這個函數,但是一點概念一點都沒有,完全跟著老師後一個字一個字的敲,現在大概能理解使用儲存映射的過程,至於什麼二級緩衝,一級緩衝,感覺需要到實際項目中才能感受到。

(全文完)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.