您好,登錄后才能下訂單哦!
什么是mmap()函數,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
mmap()函數將一個文件或者其它對象映射盡內存。文件被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最后一個頁不被使用的空間將會清零。 mmap()系統調用使得進程之間通過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間后,進程可以像訪問普通內存一樣對文件進行訪問,不必再調用read(),write()等操作。
注:實際上,mmap()系統調用并不是完全為了共享內存而設計的。它本身提供了不同于一般對普通文件的訪問方式,進程可以像讀寫內存一樣對普通文件操作。POSIX或系統V的共享內存IPC則純粹用于提供共享的目地,當然mmap()實現共享內存也是其主要應用之一。
Mmap()函數主要有3個用途:將一個普通文件映射到內存中,通常在需要對文件進行頻繁讀寫操作時使用,這樣用內存讀寫取代I/O讀寫,以獲得較高的性能將特殊文件進行匿名內存映射,可以為關聯進程提供共享內存空間為無關聯的進程提供共享內存空間,一般也是將一個普通文件映射到內存。 Linux提供了內存映射函數mmap,它把文件內容映射到一段內存上(準確來說是虛擬內存上),通過對著段內存的讀取和修改,實現對文件的讀取和修改。
一、mmap()函數的用法
#include Void*mmap(void *start, size_t length, int port, int flags, int fd,off_t offsize);
參數的意義: Start:指向欲映射的內存初始地址,通常設為NULL,代表讓系統自動選定地址,映射成功后返回該地址。 Length: 代表將文件中的多大的部分映射到內存。 Port: 映射區域的保護方式 PROT_EXEC映射區域可被執行 PROT_READ映射區域可被讀取 PROT_WRITE映射區域可被寫入 PROT_NONE映射區域不能存取 Flags:影響映射區域的各種屬性。在調用mmap()時必須指定MAP_SHARED或MAP_PRIVATE MAP_FIXED如果參數start所指的地址無法成功建立映射時,則放棄映射,不對地址做修正。 MAP_SHARED對映射區域的寫入數據會復制會文件內,而且允許其它映射文件的進程共享。 MAP_PRIVATE對映射區域的寫入操作會產生一個映射文件的復制,即私人的“寫時復制”對此區域的任何修改都不會寫回原來的文件內容。 MAP_ANONYMOUS建立匿名映射。此時會忽略參數fd,不涉及文件,而且映射區域無法和其他進程共享。 MAP_DENYWRITE只允許對映射區域的寫入操作,其他對文件直接寫入的操作將會被拒絕。 MAP_LOCKED將映射區域鎖定住,這表示該區域不會被置換(swap)。 fd:要映射到內存中的文件描述符。如果使用匿名內存映射時,即flags中設置了MAP_ANONYMOUS,fd設為-1。有些系統不支持匿名內存映射,則可以使用fopen打開/dev/zero文件,然后對該文件進行映射,可以同樣達到匿名內存映射的效果。 offset:文件映射的偏移量,通常設置為0,代表從文件最前方開始對應,offset必須是分頁大小的整數倍。 返回值:若映射成功則返回映射區的內存起始地址,否則返回MAP_FAILED(-1),錯誤原因存于errno 中。
二、系統調用mmap()用于共享內存的兩種方式:(1)使用普通文件提供的內存映射: 適用于任何進程之間。此時,需要打開或創建一個文件,然后再調用mmap() 典型調用代碼如下:
fd=open(name, flag, mode);if(fd<0) ... ptr=mmap(NULL, len ,PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0);
(2)使用特殊文件提供匿名內存映射: 適用于具有親緣關系的進程之間。由于父子進程特殊的親緣關系,在父進程中先調用mmap(),然后調用fork()。那么在調用fork()之后,子進程繼承父進程匿名映射后的地址空間,同樣也繼承mmap()返回的地址,這樣,父子進程就可以通過映射區域進行通信了。注意,這里不是一般的繼承關系。一般來說,子進程單獨維護從父進程繼承下來的一些變量。而mmap()返回的地址,卻由父子進程共同維護。對于具有親緣關系的進程實現共享內存最好的方式應該是采用匿名內存映射的方式。此時,不必指定具體的文件,只要設置相應的標志即可。
三、一個用mmap函數進行文件拷貝的例子* 用open系統調用打開文件,并返回描述符fd。這里要注意使用truncate函數來確定要寫入文件的大小。一般是用stat系列的函數來獲取源文件的大小,然后通過truncate函數修改目的文件的大小。
fd_s = open("2.c", O_RDONLY, S_IRUSR | S_IWUSR); fd_d = open("file.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); //獲取文件屬性 fstat(fd_s, &m_stat); //修改文件的大小 truncate("file.txt", m_stat.st_size);
* 用mmap建立內存映射,并返回映射首地址指針start.
s_ptr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd_s, 0); d_ptr = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, fd_d, 0); if (d_ptr == MAP_FAILED) { printf("mmap error: %s\n", strerror(errno)); return ; }
* 對映射(文件)進行各種操作, 顯示(printf),修改(sprintf)。這里是用memcpy()函數實現文件的拷貝
memcpy(d_ptr, s_ptr, len);
* 用munmap(void *start, size_tlenght)關閉內存映射.
munmap(s_ptr, len); munmap(d_ptr, len);
* 用close系統調用關閉文件fd. 自己再寫這個程序的時候又到了一個比較奇葩的問題。程序寫好時運行的錯誤是段錯誤,調式發現是memcpy函數拷貝出錯。然后我回過頭來檢查代碼,發現程序沒有什么問題,然后又運行了一遍,錯誤變成了:mmaperror: bad filedescriptor。然后我就進行了調試,結果發現是第二個調用mmap函數的返回值是-1,也就是說沒有返回正確的初始地址。這兩次不一樣的錯誤讓我迷惑了,所以就找到了大神給看看代碼,結果大神剛坐下,運行程序就正確了,沒有做任何修改,這真的就是傳說中的人品問題嗎?不理解!然后我們謝了個腳本,讓程序執行1000次,看看會不會又一次出錯的幾率,但是執行下來仍然沒有任何錯誤,大神默默離開了。。一直都想不明白這兩次錯誤是怎樣產生的?有時怎樣自動變為正確的?真是費解,還請高手指導。~~~~
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。