日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

mmap原理简析

發(fā)布時間:2025/3/21 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mmap原理简析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

共享內(nèi)存可以說是最有用的進程間通信方式,也是最快的IPC形式, 因為進程可以直接讀寫內(nèi)存,而不需要任何

數(shù)據(jù)的拷貝。對于像管道和消息隊列等通信方式,則需要在內(nèi)核和用戶空間進行四次的數(shù)據(jù)拷貝,而共享內(nèi)存則

只拷貝兩次數(shù)據(jù): 一次從輸入文件到共享內(nèi)存區(qū),另一次從共享內(nèi)存區(qū)到輸出文件。實際上,進程之間在共享內(nèi)

存時,并不總是讀寫少量數(shù)據(jù)后就解除映射,有新的通信時,再重新建立共享內(nèi)存區(qū)域。而是保持共享區(qū)域,直

到通信完畢為止,這樣,數(shù)據(jù)內(nèi)容一直保存在共享內(nèi)存中,并沒有寫回文件。共享內(nèi)存中的內(nèi)容往往是在解除映

射時才寫回文件的。因此,采用共享內(nèi)存的通信方式效率是非常高的。

?

一. 傳統(tǒng)文件訪問

UNIX訪問文件的傳統(tǒng)方法是用open打開它們, 如果有多個進程訪問同一個文件, 則每一個進程在自己的地址空間都包含有該

文件的副本,這不必要地浪費了存儲空間. 下圖說明了兩個進程同時讀一個文件的同一頁的情形. 系統(tǒng)要將該頁從磁盤讀到高

速緩沖區(qū)中, 每個進程再執(zhí)行一個存儲器內(nèi)的復(fù)制操作將數(shù)據(jù)從高速緩沖區(qū)讀到自己的地址空間.

?

二. 共享存儲映射

現(xiàn)在考慮另一種處理方法: 進程A和進程B都將該頁映射到自己的地址空間, 當(dāng)進程A第一次訪問該頁中的數(shù)據(jù)時, 它生成一

個缺頁中斷. 內(nèi)核此時讀入這一頁到內(nèi)存并更新頁表使之指向它.以后, 當(dāng)進程B訪問同一頁面而出現(xiàn)缺頁中斷時, 該頁已經(jīng)在

內(nèi)存, 內(nèi)核只需要將進程B的頁表登記項指向次頁即可. 如下圖所示:?

?

三、mmap()及其相關(guān)系統(tǒng)調(diào)用

mmap()系統(tǒng)調(diào)用使得進程之間通過映射同一個普通文件實現(xiàn)共享內(nèi)存。普通文件被映射到進程地址空間后,進程可以向訪

問普通內(nèi)存一樣對文件進行訪問,不必再調(diào)用read(),write()等操作。

?

mmap()系統(tǒng)調(diào)用形式如下:

void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset )?

mmap的作用是映射文件描述符fd指定文件的 [off,off + len]區(qū)域至調(diào)用進程的[addr, addr + len]的內(nèi)存區(qū)域, 如下圖所示:

?

參數(shù)fd為即將映射到進程空間的文件描述字,一般由open()返回,同時,fd可以指定為-1,此時須指定flags參數(shù)中的

MAP_ANON,表明進行的是匿名映射(不涉及具體的文件名,避免了文件的創(chuàng)建及打開,很顯然只能用于具有親緣關(guān)系的

進程間通信)。

len是映射到調(diào)用進程地址空間的字節(jié)數(shù),它從被映射文件開頭offset個字節(jié)開始算起。

prot 參數(shù)指定共享內(nèi)存的訪問權(quán)限。可取如下幾個值的或:PROT_READ(可讀) , PROT_WRITE (可寫), PROT_EXEC (可執(zhí)行), PROT_NONE(不可訪問)。

flags由以下幾個常值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,其中,MAP_SHARED , MAP_PRIVATE必

選其一,而MAP_FIXED則不推薦使用。

offset參數(shù)一般設(shè)為0,表示從文件頭開始映射。

參數(shù)addr指定文件應(yīng)被映射到進程空間的起始地址,一般被指定一個空指針,此時選擇起始地址的任務(wù)留給內(nèi)核來完成。函

數(shù)的返回值為最后文件映射到進程空間的地址,進程可直接操作起始地址為該值的有效地址。


四. mmap的兩個例子 范例中使用的測試文件 data.txt:? Xml代碼 ?
  • aaaaaaaaa??
  • bbbbbbbbb??
  • ccccccccc??
  • ddddddddd??
  • ? 1 通過共享映射的方式修改文件
    C代碼 ?
  • #include?<sys/mman.h>??
  • #include?<sys/stat.h>??
  • #include?<fcntl.h>??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<unistd.h>??
  • #include?<error.h>??
  • ??
  • #define?BUF_SIZE?100??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????int?fd,?nread,?i;??
  • ????struct?stat?sb;??
  • ????char?*mapped,?buf[BUF_SIZE];??
  • ??
  • ????for?(i?=?0;?i?<?BUF_SIZE;?i++)?{??
  • ????????buf[i]?=?'#';??
  • ????}??
  • ??
  • ????/*?打開文件?*/??
  • ????if?((fd?=?open(argv[1],?O_RDWR))?<?0)?{??
  • ????????perror("open");??
  • ????}??
  • ??
  • ????/*?獲取文件的屬性?*/??
  • ????if?((fstat(fd,?&sb))?==?-1)?{??
  • ????????perror("fstat");??
  • ????}??
  • ??
  • ????/*?將文件映射至進程的地址空間?*/??
  • ????if?((mapped?=?(char?*)mmap(NULL,?sb.st_size,?PROT_READ?|???
  • ????????????????????PROT_WRITE,?MAP_SHARED,?fd,?0))?==?(void?*)-1)?{??
  • ????????perror("mmap");??
  • ????}??
  • ??
  • ????/*?映射完后,?關(guān)閉文件也可以操縱內(nèi)存?*/??
  • ????close(fd);??
  • ??
  • ????printf("%s",?mapped);??
  • ??
  • ????/*?修改一個字符,同步到磁盤文件?*/??
  • ????mapped[20]?=?'9';??
  • ????if?((msync((void?*)mapped,?sb.st_size,?MS_SYNC))?==?-1)?{??
  • ????????perror("msync");??
  • ????}??
  • ??
  • ????/*?釋放存儲映射區(qū)?*/??
  • ????if?((munmap((void?*)mapped,?sb.st_size))?==?-1)?{??
  • ????????perror("munmap");??
  • ????}??
  • ??
  • ????return?0;??
  • }??
  • ? 2 私有映射無法修改文件
    /* 將文件映射至進程的地址空間 */ if ((mapped = (char *)mmap(NULL, sb.st_size, PROT_READ |? ? ? ? ? ? ? ? ? ? ? PROT_WRITE, MAP_PRIVATE, fd, 0)) == (void *)-1) { ? ? perror("mmap"); }
    五. 使用共享映射實現(xiàn)兩個進程之間的通信 兩個程序映射同一個文件到自己的地址空間, 進程A先運行, 每隔兩秒讀取映射區(qū)域, 看是否發(fā)生變化.? 進程B后運行, 它修改映射區(qū)域, 然后推出, 此時進程A能夠觀察到存儲映射區(qū)的變化 進程A的代碼: C代碼 ?
  • #include?<sys/mman.h>??
  • #include?<sys/stat.h>??
  • #include?<fcntl.h>??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<unistd.h>??
  • #include?<error.h>??
  • ??
  • #define?BUF_SIZE?100??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????int?fd,?nread,?i;??
  • ????struct?stat?sb;??
  • ????char?*mapped,?buf[BUF_SIZE];??
  • ??
  • ????for?(i?=?0;?i?<?BUF_SIZE;?i++)?{??
  • ????????buf[i]?=?'#';??
  • ????}??
  • ??
  • ????/*?打開文件?*/??
  • ????if?((fd?=?open(argv[1],?O_RDWR))?<?0)?{??
  • ????????perror("open");??
  • ????}??
  • ??
  • ????/*?獲取文件的屬性?*/??
  • ????if?((fstat(fd,?&sb))?==?-1)?{??
  • ????????perror("fstat");??
  • ????}??
  • ??
  • ????/*?將文件映射至進程的地址空間?*/??
  • ????if?((mapped?=?(char?*)mmap(NULL,?sb.st_size,?PROT_READ?|???
  • ????????????????????PROT_WRITE,?MAP_SHARED,?fd,?0))?==?(void?*)-1)?{??
  • ????????perror("mmap");??
  • ????}??
  • ??
  • ????/*?文件已在內(nèi)存,?關(guān)閉文件也可以操縱內(nèi)存?*/??
  • ????close(fd);??
  • ??????
  • ????/*?每隔兩秒查看存儲映射區(qū)是否被修改?*/??
  • ????while?(1)?{??
  • ????????printf("%s\n",?mapped);??
  • ????????sleep(2);??
  • ????}??
  • ??
  • ????return?0;??
  • }??
  • ? 進程B的代碼: C代碼 ?
  • #include?<sys/mman.h>??
  • #include?<sys/stat.h>??
  • #include?<fcntl.h>??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<unistd.h>??
  • #include?<error.h>??
  • ??
  • #define?BUF_SIZE?100??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????int?fd,?nread,?i;??
  • ????struct?stat?sb;??
  • ????char?*mapped,?buf[BUF_SIZE];??
  • ??
  • ????for?(i?=?0;?i?<?BUF_SIZE;?i++)?{??
  • ????????buf[i]?=?'#';??
  • ????}??
  • ??
  • ????/*?打開文件?*/??
  • ????if?((fd?=?open(argv[1],?O_RDWR))?<?0)?{??
  • ????????perror("open");??
  • ????}??
  • ??
  • ????/*?獲取文件的屬性?*/??
  • ????if?((fstat(fd,?&sb))?==?-1)?{??
  • ????????perror("fstat");??
  • ????}??
  • ??
  • ????/*?私有文件映射將無法修改文件?*/??
  • ????if?((mapped?=?(char?*)mmap(NULL,?sb.st_size,?PROT_READ?|???
  • ????????????????????PROT_WRITE,?MAP_PRIVATE,?fd,?0))?==?(void?*)-1)?{??
  • ????????perror("mmap");??
  • ????}??
  • ??
  • ????/*?映射完后,?關(guān)閉文件也可以操縱內(nèi)存?*/??
  • ????close(fd);??
  • ??
  • ????/*?修改一個字符?*/??
  • ????mapped[20]?=?'9';??
  • ???
  • ????return?0;??
  • }??
  • ? 六. 通過匿名映射實現(xiàn)父子進程通信 C代碼 ?
  • #include?<sys/mman.h>??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<unistd.h>??
  • ??
  • #define?BUF_SIZE?100??
  • ??
  • int?main(int?argc,?char**?argv)??
  • {??
  • ????char????*p_map;??
  • ??
  • ????/*?匿名映射,創(chuàng)建一塊內(nèi)存供父子進程通信?*/??
  • ????p_map?=?(char?*)mmap(NULL,?BUF_SIZE,?PROT_READ?|?PROT_WRITE,??
  • ????????????MAP_SHARED?|?MAP_ANONYMOUS,?-1,?0);??
  • ??
  • ????if(fork()?==?0)?{??
  • ????????sleep(1);??
  • ????????printf("child?got?a?message:?%s\n",?p_map);??
  • ????????sprintf(p_map,?"%s",?"hi,?dad,?this?is?son");??
  • ????????munmap(p_map,?BUF_SIZE);?//實際上,進程終止時,會自動解除映射。??
  • ????????exit(0);??
  • ????}??
  • ??
  • ????sprintf(p_map,?"%s",?"hi,?this?is?father");??
  • ????sleep(2);??
  • ????printf("parent?got?a?message:?%s\n",?p_map);??
  • ??
  • ????return?0;??
  • }??
  • ?

    ?

    七. 對mmap()返回地址的訪問 linux采用的是頁式管理機制。對于用mmap()映射普通文件來說,進程會在自己的地址空間新增一塊空間,空間大 小由mmap()的len參數(shù)指定,注意,進程并不一定能夠?qū)θ啃略隹臻g都能進行有效訪問。進程能夠訪問的有效地址大小取決于文件被映射部分的大小。簡單的說,能夠容納文件被映射部分大小的最少頁面?zhèn)€數(shù)決定了進程從mmap()返回的地址開始,能夠有效訪問的地址空間大小。超過這個空間大小,內(nèi)核會根據(jù)超過的嚴重程度返回發(fā)送不同的信號給進程。可用如下圖示說明:

    ?

    總結(jié)一下就是, 文件大小, mmap的參數(shù) len 都不能決定進程能訪問的大小, 而是容納文件被映射部分的最小頁面數(shù)決定

    進程能訪問的大小. 下面看一個實例:

    ?

    ?

    C代碼 ?
  • #include?<sys/mman.h>??
  • #include?<sys/types.h>??
  • #include?<sys/stat.h>??
  • #include?<fcntl.h>??
  • #include?<unistd.h>??
  • #include?<stdio.h>??
  • ??
  • int?main(int?argc,?char**?argv)??
  • {??
  • ????int?fd,i;??
  • ????int?pagesize,offset;??
  • ????char?*p_map;??
  • ????struct?stat?sb;??
  • ??
  • ????/*?取得page?size?*/??
  • ????pagesize?=?sysconf(_SC_PAGESIZE);??
  • ????printf("pagesize?is?%d\n",pagesize);??
  • ??
  • ????/*?打開文件?*/??
  • ????fd?=?open(argv[1],?O_RDWR,?00777);??
  • ????fstat(fd,?&sb);??
  • ????printf("file?size?is?%zd\n",?(size_t)sb.st_size);??
  • ??
  • ????offset?=?0;???
  • ????p_map?=?(char?*)mmap(NULL,?pagesize?*?2,?PROT_READ|PROT_WRITE,???
  • ????????????MAP_SHARED,?fd,?offset);??
  • ????close(fd);??
  • ??????
  • ????p_map[sb.st_size]?=?'9';??/*?導(dǎo)致總線錯誤?*/??
  • ????p_map[pagesize]?=?'9';????/*?導(dǎo)致段錯誤?*/??
  • ??
  • ????munmap(p_map,?pagesize?*?2);??
  • ??
  • ????return?0;??
  • }
  • 總結(jié)

    以上是生活随笔為你收集整理的mmap原理简析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 成人手机在线免费视频 | 欧美日韩国产亚洲沙发 | 秋霞午夜鲁丝一区二区老狼 | 青青草五月天 | 日韩成人激情 | 国产亚洲精品美女久久久久 | 精品黑人一区二区三区在线观看 | 男女视频一区二区 | 少妇又色又紧又大爽又刺激 | av中文字幕免费观看 | 精品成人一区二区三区久久精品 | 日韩在线国产精品 | 亚洲一区二区三区在线视频观看 | 国产a v一区二区三区 | 伦伦影院午夜理伦片 | 午夜激情福利视频 | 日本黄在线 | av色站 | 亚洲码视频 | 黄a视频| 国产二区一区 | 亚洲字幕在线观看 | 欧美一区二区不卡视频 | 天堂中文在线资源 | 国产在线视频一区二区三区 | 青青操av在线| 在线成人免费电影 | 日本韩国视频 | 成人午夜在线观看视频 | 国产视频第一页 | 色多多在线视频 | 日本午夜网站 | 欧美成人三区 | 最新日韩一区 | 日本a级片免费 | 亚洲无套 | 玉足调教丨vk24分钟 | 欧美少妇xx | jjzz国产 | 处破痛哭a√18成年片免费 | 殴美黄色大片 | 成人免费激情视频 | 91超碰在线| 91日批 | 国产精品宾馆在线精品酒店 | 韩国成人免费视频 | 欧美精品第二页 | www日本在线观看 | 国产免费脚交足视频在线观看 | 九九在线观看免费高清版 | 快播视频在线观看 | 国产精品久久9 | 亚洲国产精品无码专区 | 桥本有菜aⅴ一区二区三区 在线午夜电影 | 日韩亚洲国产精品 | 91av久久| 人人草人 | 少妇高潮露脸国语对白 | 97视频久久 | 91精品国产乱码 | 久久黄网| 自由成熟xxxx色视频 | 免费的黄色的网站 | 森泽佳奈作品在线观看 | 毛片毛片 | 国产精品亚洲第一 | 波多野结衣视频网站 | 鲁一鲁一鲁一鲁一av | 国产在线视频卡一卡二 | 男女做事网站 | 欧美福利在线 | 国产一在线观看 | 欧美极品少妇xxxxⅹ喷水 | 91呦呦| 国产精品成人aaaa在线 | 中文亚洲欧美 | 亚欧美色图 | 午夜成人亚洲理伦片在线观看 | 亚洲人性生活视频 | 日韩美女啪啪 | 美女露胸无遮挡 | 国产美女精品 | 久久久无码人妻精品一区 | 黄页网站在线播放 | 人人插人人爽 | 亚洲激情自拍偷拍 | av美女在线观看 | 91精品国产一区二区三区香蕉 | 久久99国产精品久久99 | 狠狠久久 | 亚洲综合图色40p | 日韩中文字幕精品视频 | 国产精品五区 | 日韩高清影视 | wwwxxx色| 欧美激情一二三区 | 91精品婷婷国产综合久久竹菊 | 欧美激情午夜 | 日韩精品一区二区av |