日韩性视频-久久久蜜桃-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九九 | 久操伊人网 | 已满十八岁免费观看全集动漫 | 亚洲最大激情网 | 黄色小视频在线播放 | 91精品区 | 日本啊啊视频 | 国产在线观看免费 | 麻豆精品在线播放 | 少妇高潮迭起 | 男人女人拔萝卜视频 | 国产第一页视频 | 国产成人精品亚洲日本在线观看 | 一区二区中文 | 亚洲一区二区在线 | 精品视频入口 | 国产成人高清视频 | 青青草原一区二区 | 国产精品久久综合青草亚洲AV | av网站在线免费播放 | 亚洲午夜视频在线观看 | 亚洲精品一线二线三线 | 先锋影音av资源网站 | 色美av| 国产午夜精品一区二区三区四区 | 亚洲一区二区在线 | 亚洲播放 | 日韩高清在线观看一区 | 午夜伦视频 | 久久亚洲av无码精品色午夜麻豆 | 国产欧美一级片 | 白浆在线 | 午夜日韩福利 | 九九av在线 | 91精品影视 | 国产三级三级三级三级三级 | 国产专区一区二区 | 操xxxx| 女人免费视频 | 小俊大肉大捧一进一出好爽 | 黄色在线免费网站 | 精品久久香蕉国产线看观看亚洲 | 欧美aⅴ| 秋霞福利视频 | 日韩一卡二卡三卡 | 麻豆视频在线看 | 视频在线观看一区 | 欧美一级α片 | 国产特级片| 亚洲av成人精品午夜一区二区 | 邻居少妇张开腿让我爽了在线观看 | 成年人网站黄色 | 91porny九色 | 欧美老熟妇喷水 | 一级少妇片 | 色视频免费 | 国产女人18水真多18精品一级做 | 中国一级免费毛片 | 美女又黄又免费 | 国产又粗又爽视频 | 最近中文字幕mv | 91免费视频国产 | 欧美一区在线看 | 亚洲福利视频导航 | 午夜va | 制服丝袜第一页在线观看 | 欧产日产国产精品98 | 亚洲视频一二三四 | 国产女人18毛片水真多 | 97精品国产 | 九月色婷婷 | 夏目彩春娇喘呻吟高潮迭起 | 一区二区久久久 | 久久国产精品国产精品 | 伊人春色在线视频 | 污视频在线 | 亲子伦视频一区二区三区 | 人人人射 | 激情啪啪网站 | 越南a级片 | 国产乱论视频 | 亚洲乱码国产乱码精品精98午夜 | 美女一级视频 | 亚洲成人精品一区二区三区 | 国产一二在线 | 韩日视频在线 | 久久精品国产亚洲av麻豆色欲 | 色94色欧美 | 日韩视频免费观看高清完整版 | www日本色| 日本人性爱视频 | 亚洲鲁鲁| 夜夜嗨av一区二区三区四区 | 人人干人人舔 |