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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

mmap映射区和shm共享内存的区别总结

發(fā)布時(shí)間:2024/1/23 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mmap映射区和shm共享内存的区别总结 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

linux中的兩種共享內(nèi)存。一種是我們的IPC通信System V版本的共享內(nèi)存,另外的一種就是我們今天提到的存儲映射I/O(mmap函數(shù))

在說mmap之前我們先說一下普通的讀寫文件的原理,進(jìn)程調(diào)用read或是write后會(huì)陷入內(nèi)核,因?yàn)檫@兩個(gè)函數(shù)都是系統(tǒng)調(diào)用,進(jìn)入系統(tǒng)調(diào)用后,內(nèi)核開始讀寫文件,假設(shè)內(nèi)核在讀取文件,內(nèi)核首先把文件讀入自己的內(nèi)核空間,讀完之后進(jìn)程在內(nèi)核回歸用戶態(tài),內(nèi)核把讀入內(nèi)核內(nèi)存的數(shù)據(jù)再copy進(jìn)入進(jìn)程的用戶態(tài)內(nèi)存空間。實(shí)際上我們同一份文件內(nèi)容相當(dāng)于讀了兩次,先讀入內(nèi)核空間,再從內(nèi)核空間讀入用戶空間。


 Linux提供了內(nèi)存映射函數(shù)mmap, 它把文件內(nèi)容映射到一段內(nèi)存上(準(zhǔn)確說是虛擬內(nèi)存上), 通過對這段內(nèi)存的讀取和修改, 實(shí)現(xiàn)對文件的讀取和修改,mmap()系統(tǒng)調(diào)用使得進(jìn)程之間可以通過映射一個(gè)普通的文件實(shí)現(xiàn)共享內(nèi)存。普通文件映射到進(jìn)程地址空間后,進(jìn)程可以向訪問內(nèi)存的方式對文件進(jìn)行訪問,不需要其他系統(tǒng)調(diào)用(read,write)去操作。

mmap圖示例:

mmap系統(tǒng)調(diào)用介紹
?

?
  • ? void *mmap(void *addr, size_t length, int prot, int flags,

  • ? ? ? ? ? ? ? ? ? int fd, off_t offset);

  • 這就是mmap系統(tǒng)調(diào)用的接口,mmap函數(shù)成功返回指向內(nèi)存區(qū)域的指針,圖上的進(jìn)程的地址空間的開始地址就是mmap函數(shù)的返回值,失敗返回MAP_FAILED。

    addr,某個(gè)特定的地址作為起始地址,當(dāng)被設(shè)置為NULL,系統(tǒng)會(huì)在地址空間選擇一塊合適的內(nèi)存區(qū)域。

    length說的是內(nèi)存段的長度。

    prot是用來設(shè)定內(nèi)存段的訪問權(quán)限。

    prot參數(shù)?? ?說明
    PROT_READ?? ?內(nèi)存段可讀
    PROT_WRITE?? ?內(nèi)存段可寫
    PROT_EXEC?? ?內(nèi)存段可執(zhí)行
    PROT_NONE?? ?內(nèi)存段不能被訪問
    flags參數(shù)控制內(nèi)存段內(nèi)容被修改以后程序的行為。

    flags參數(shù)?? ?說明
    MAP_SHARED?? ?進(jìn)程間共享內(nèi)存,對該內(nèi)存段修改反映到映射文件中。提供了POSIX共享內(nèi)存
    MAP_PRIVATE?? ?內(nèi)存段為調(diào)用進(jìn)程所私有。對該內(nèi)存段的修改不會(huì)反映到映射文件
    MAP_ANNOYMOUS?? ?這段內(nèi)存不是從文件映射而來的。內(nèi)容被初始化為全0
    MAP_FIXED?? ?內(nèi)存段必須位于start參數(shù)指定的地址處,start必須是頁大小的整數(shù)倍(4K整數(shù)倍)
    MAP_HUGETLB?? ?按照大內(nèi)存頁面來分配內(nèi)存空間
    fd參數(shù)是用來被映射文件對應(yīng)的文件描述符。通過open系統(tǒng)調(diào)用得到。offset設(shè)定從何處進(jìn)行映射。

    mmap使用注意事項(xiàng):

    利用mmap進(jìn)行非血緣進(jìn)程間通信代碼:

    ?
  • #include<stdio.h>

  • #include<stdlib.h>

  • #include<unistd.h>

  • #include<fcntl.h>

  • #include<sys/types.h>

  • #include<sys/stat.h>

  • #include<sys/mman.h>

  • #include<string.h>

  • ?

  • struct STU

  • {

  • ?? ?int age;

  • ?? ?char name[20];

  • ?? ?char sex;

  • };

  • ?

  • int main(int argc,char *argv[]) //這個(gè)進(jìn)程用于創(chuàng)建映射區(qū)進(jìn)行寫。

  • {

  • ?? ?if(argc != 2)

  • ?? ?{

  • ?? ??? ?printf("./a,out ?file");

  • ?? ??? ?exit(1);

  • ?? ?}

  • ?

  • ?? ?struct STU student = {10,"xiaoming",'m'};

  • ?

  • ?? ?int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0644);

  • ?? ?if(fd < 0)

  • ?? ?{

  • ?? ??? ?perror("open");

  • ?? ??? ?exit(2);

  • ?? ?}

  • ?? ?ftruncate(fd,sizeof(struct STU)); //文件拓展大小。

  • ?? ?

  • ?? ?struct STU *p = (struct STU*)mmap(NULL,sizeof(struct STU),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//創(chuàng)建一個(gè)結(jié)構(gòu)體大小的共享映射區(qū)。共享映射區(qū)我們可以當(dāng)做數(shù)組區(qū)看待。

  • ?? ?if(p == MAP_FAILED)

  • ?? ?{

  • ?? ??? ?perror("mmap");

  • ?? ??? ?exit(3);

  • ?? ?}

  • ?? ?close(fd); //關(guān)閉不用的文件描述符。

  • ?? ?while(1)

  • ?? ?{

  • ?? ??? ?memcpy(p,&student,sizeof(student));

  • ?? ??? ?student.age++;

  • ?? ??? ?sleep(1);

  • ?? ?}

  • ?? ?int ret = munmap(p,sizeof(student));

  • ?? ?if(ret < 0)

  • ?? ?{

  • ?? ??? ?perror("mmumap");

  • ?? ??? ?exit(4);

  • ?? ?}

  • ?

  • ?? ?return 0;

  • }

  • ?
  • #include<stdio.h>

  • #include<stdlib.h>

  • #include<unistd.h>

  • #include<fcntl.h>

  • #include<sys/types.h>

  • #include<sys/stat.h>

  • #include<sys/mman.h>

  • ?

  • struct STU

  • {

  • ?? ?int age;

  • ?? ?char name[20];

  • ?? ?char sex;

  • };

  • ?

  • int main(int argc,char *argv[]) //這個(gè)進(jìn)程讀

  • {

  • ?? ?if(argc != 2)

  • ?? ?{

  • ?? ??? ?printf("./a,out ?file");

  • ?? ??? ?exit(1);

  • ?? ?}

  • ?

  • ?

  • ?? ?int fd = open(argv[1],O_RDONLY,0644);

  • ?? ?if(fd < 0)

  • ?? ?{

  • ?? ??? ?perror("open");

  • ?? ??? ?exit(2);

  • ?? ?}

  • ?? ?

  • ?? ?struct STU student;

  • ?

  • ?? ?struct STU *p = (struct STU*)mmap(NULL,sizeof(struct STU),PROT_READ,MAP_SHARED,fd,0);

  • ?? ?if(p == MAP_FAILED)

  • ?? ?{

  • ?? ??? ?perror("mmap");

  • ?? ??? ?exit(3);

  • ?? ?}

  • ?? ?close(fd);

  • ?? ?int i = 0;

  • ?? ?while(1)

  • ?? ?{

  • ?? ??? ?

  • ?? ??? ?printf("id = %d\tname = %s\t%c\n",p->age,p->name,p->sex);?? ?

  • ?? ??? ?sleep(2);

  • ?? ?}

  • ?? ?int ret = munmap(p,sizeof(student));

  • ?? ?if(ret < 0)

  • ?? ?{

  • ?? ??? ?perror("mmumap");

  • ?? ??? ?exit(4);

  • ?? ?}

  • ?

  • ?? ?return 0;

  • }


  • 代碼截圖:


    分析:因?yàn)橹粍?chuàng)建一個(gè)結(jié)構(gòu)體大小的共享內(nèi)存,后面寫入的數(shù)據(jù)把前面寫入的數(shù)據(jù)覆蓋了。

    shm調(diào)用介紹:參見上一篇博客
    http://blog.csdn.net/hj605635529/article/details/67636526

    shm圖示例:


    (1)通過int shmget(key_t key, size_t size, int shmflg);在物理內(nèi)存創(chuàng)建一個(gè)共享內(nèi)存,返回共享內(nèi)存的編號。
    (2)通過void *shmat(int shmid, constvoid shmaddr,int shmflg);連接成功后把共享內(nèi)存區(qū)對象映射到調(diào)用進(jìn)程的地址空間
    (3)通過void *shmdt(constvoid* shmaddr);斷開用戶級頁表到共享內(nèi)存的那根箭頭。
    (4)通過int shmctl(int shmid, int cmd, struct shmid_ds* buf);釋放物理內(nèi)存中的那塊共享內(nèi)存。

    總結(jié)mmap和shm:
    1、mmap是在磁盤上建立一個(gè)文件,每個(gè)進(jìn)程地址空間中開辟出一塊空間進(jìn)行映射。
    而對于shm而言,shm每個(gè)進(jìn)程最終會(huì)映射到同一塊物理內(nèi)存。shm保存在物理內(nèi)存,這樣讀寫的速度要比磁盤要快,但是存儲量不是特別大。
    2、相對于shm來說,mmap更加簡單,調(diào)用更加方便,所以這也是大家都喜歡用的原因。
    3、另外mmap有一個(gè)好處是當(dāng)機(jī)器重啟,因?yàn)閙map把文件保存在磁盤上,這個(gè)文件還保存了操作系統(tǒng)同步的映像,所以mmap不會(huì)丟失,但是shmget就會(huì)丟失。

    總結(jié)

    以上是生活随笔為你收集整理的mmap映射区和shm共享内存的区别总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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