上一篇学习了共享内存: http://www.cnblogs.com/charlesblc/p/6142139.html

根据这个 http://blog.chinaunix.net/uid-26335251-id-3493125.html

再来一篇:

1. 共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制。共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿名映射)机制实现,也可以通过系统V共享内存机制实现。

应用接口和原理很简单,内部机制复杂。为了实现更安全通信,往往还与信号灯等同步机制共同使用。

mmap的机制如:就是在磁盘上建立一个文件,每个进程存储器里面,单独开辟一个空间来进行映射。如果多进程的话,那么不会对实际的物理存储器(主存)消耗太大。

shm的机制:每个进程的共享内存都直接映射到实际内存里面。

结论:

1、mmap保存到实际硬盘,实际存储并没有反映到主存上。优点:储存量可以很大(多于主存);缺点:进程间读取和写入速度要比主存的要慢。

2、shm保存到物理存储器(主存),实际的储存量直接反映到主存上。优点,进程间访问速度(读写)比磁盘要快;缺点,储存量不能非常大(多于主存)

使用上看:如果分配的存储量不大,那么使用shm;如果存储量大,那么使用shm。

mmap就是一个文件操作。

mmap函数是unix/linux下的系统调用,来看《Unix Netword programming》卷二12.2节有详细介绍。

mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
          mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再 调用read(),write()等操作。mmap并不分配空间, 只是将文件映射到调用进程的地址空间里, 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后用msync()同步一下, 你所写的内容就保存到文件里了. 不过这种方式没办法增加文件的长度, 因为要映射的长度在调用mmap()的时候就决定了.

简单说就是把一个文件的内容在内存里面做一个映像,内存比磁盘快些。
基本上它是把一个档案对应到你的virtual memory 中的一段,并传回一个指针。

系统调用mmap()用于共享内存的两种方式: 
(1)使用普通文件提供的内存映射:适用于任何进程之间;此时,需要打开或创建一个文件,然后再调用mmap();典型调用代码如下: 
fd=open(name, flag, mode); 
if(fd<0) 
... 
ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0); 通过mmap()实现共享内存的通信方式有许多特点和要注意的地方,我们将在范例中进行具体说明。 
(2)使用特殊文件提供匿名内存映射:适用于具有亲缘关系的进程之间;由于父子进程特殊的亲缘关系,在父进程中先调用mmap(),然后调用fork()。那么在调用fork()之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap()返回的地址,这样,父子进程就可以通过映射区域进行通信了。注意,这里不是一般的继承关系。一般来说,子进程单独维护从父进程继承下来的一些变量。而mmap()返回的地址,却由父子进程共同维护。

1、mmap()系统调用形式如下:

void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset ) 
参数fd为即将映射到进程空间的文件描述字,一般由open()返回,同时,fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的进程间通信)。len是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。prot 参数指定共享内存的访问权限。可取如下几个值的或:PROT_READ(可读) , PROT_WRITE (可写), PROT_EXEC (可执行), PROT_NONE(不可访问)。flags由以下几个常值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,其中,MAP_SHARED , MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。offset参数一般设为0,表示从文件头开始映射。参数addr指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。这里不再详细介绍mmap()的参数,读者可参考mmap()手册页获得进一步的信息。

三、mmap()范例

下面将给出使用mmap()的两个范例:范例1给出两个进程通过映射普通文件实现共享内存通信;范例2给出父子进程通过匿名映射实现共享内存。系统调用mmap()有许多有趣的地方,下面是通过mmap()映射普通文件实现进程间的通信的范例,我们通过该范例来说明mmap()实现共享内存的特点及注意事项。

范例1:两个进程通过映射普通文件实现共享内存通信

  1. /*-------------map_normalfile1.c-----------*/
  2. #include <sys/mman.h>
  3. #include <sys/types.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. typedef struct{
  7. char name[];
  8. int age;
  9. }people;
  10. main(int argc, char** argv) // map a normal file as shared mem:
  11. {
  12. int fd,i;
  13. people *p_map;
  14. char temp;
  15.  
  16. fd=open(argv[],O_CREAT|O_RDWR|O_TRUNC,);
  17. lseek(fd,sizeof(people)*-,SEEK_SET);
  18. write(fd,"",);
  19.  
  20. p_map = (people*) mmap( NULL,sizeof(people)*,PROT_READ|PROT_WRITE,MAP_SHARED,fd, );
  21. close( fd );
  22. temp = 'a';
  23. for(i=; i<; i++)
  24. {
  25. temp += ;
  26. memcpy( ( *(p_map+i) ).name, &temp, );
  27. ( *(p_map+i) ).age = +i;
  28. }
  29. printf(" initialize over \n ");
  30. sleep();
  31. munmap( p_map, sizeof(people)* );
  32. printf( "umap ok \n" );
  33. }
  34. /*-------------map_normalfile2.c-----------*/
  35. #include <sys/mman.h>
  36. #include <sys/types.h>
  37. #include <fcntl.h>
  38. #include <unistd.h>
  39. typedef struct{
  40. char name[];
  41. int age;
  42. }people;
  43. main(int argc, char** argv) // map a normal file as shared mem:
  44. {
  45. int fd,i;
  46. people *p_map;
  47. fd=open( argv[],O_CREAT|O_RDWR, );
  48. p_map = (people*)mmap(NULL,sizeof(people)*,PROT_READ|PROT_WRITE,MAP_SHARED,fd,);
  49. for(i = ;i<;i++)
  50. {
  51. printf( "name: %s age %d;\n",(*(p_map+i)).name, (*(p_map+i)).age );
  52. }
  53. munmap( p_map,sizeof(people)* );
  54. }

范例2:父子进程通过匿名映射实现共享内存

  1. #include <sys/mman.h>
  2. #include <sys/types.h>
  3. #include <fcntl.h>
  4. #include <unistd.h>
  5. typedef struct{
  6. char name[];
  7. int age;
  8. }people;
  9. main(int argc, char** argv)
  10. {
  11. int i;
  12. people *p_map;
  13. char temp;
  14. p_map=(people*)mmap(NULL,sizeof(people)*,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-,);
  15. if(fork() == )
  16. {
  17. sleep();
  18. for(i = ;i<;i++)
  19. printf("child read: the %d people's age is %d\n",i+,(*(p_map+i)).age);
  20. (*p_map).age = ;
  21. munmap(p_map,sizeof(people)*); //实际上,进程终止时,会自动解除映射。
  22. exit();
  23. }
  24. temp = 'a';
  25. for(i = ;i<;i++)
  26. {
  27. temp += ;
  28. memcpy((*(p_map+i)).name, &temp,);
  29. (*(p_map+i)).age=+i;
  30. }
  31. sleep();
  32. printf( "parent read: the first people,s age is %d\n",(*p_map).age );
  33. printf("umap\n");
  34. munmap( p_map,sizeof(people)* );
  35. printf( "umap ok\n" );
  36. }

这篇文章也讲了system V 共享内存:http://blog.chinaunix.net/uid-26000296-id-3421346.html

1. shmget

  1. 该函数用来创建共享内存:
  2. int shmget(key_t key, size_t size, int shmflg);
  3. 参数:
  4. key : 和信号量一样,程序需要提供一个参数key,
  5. 它有效地为共享内存段命名。
  6.  
  7. 有一个特殊的键值IPC_PRIVATE,
  8. 它用于创建一个只属于创建进程的共享内存,
  9. 通常不会用到。
  10. size: 以字节为单位指定需要共享的内存容量。
  11. shmflag: 包含9个比特的权限标志,
  12. 它们的作用与创建文件时使用的mode标志是一样。
  13. IPC_CREAT定义的一个特殊比特必须和权限标志按位或
  14. 才能创建一个新的共享内存段。
  15.  
  16. NOTE:
  17. 权限标志对共享内存非常有用,
  18. 因为它允许一个进程创建的共享内存可以被共享内存的创建者所拥有的进程写入,
  19. 同时其它用户创建的进程只能读取共享内存。
  20.  
  21. 我们可以利用这个功能来提供一种有效的对数据进行只读访问的方法,
  22. 通过将数据放共享内存并设置它的权限,
  23. 就可以避免数据被其他用户修改。
  24.  
  25. 返回值:
  26. 创建成功,则返回一个非负整数,即共享内存标识;
  27. 如果失败,则返回-.

2. shmat函数

  1. 第一次创建共享内存段时,它不能被任何进程访问。要想启动对该内存的访问,必须将其连接到一个进程的地址空间。
  2. 这个工作由shmat函数完成:
  3. void *shmat(int shm_id, const void *shm_addr, int shmflg);
  4. 参数:
  5. shm_id : shmget返回的共享内存标识。
  6. shm_add: 指定共享内存连接到当前进程中的地址位置。
  7. 它通常是一个空指针,
  8. 表示让系统来选择共享内存出现的地址。
  9. shmflg : 是一组标志。
  10. 它的两个可能取值是:
  11. SHM_RND, shm_add联合使用,
  12. 用来控制共享内存连接的地址。
  13. SHM_RDONLY, 它使连接的内存只读
  14.  
  15. 返回值:
  16. 如果调用成功, 返回一个指向共享内存第一个字节的指针;
  17. 如果失败,返回-.
  18.  
  19. 共享内存的读写权限由它的属主(共享内存的创建者),
  20. 它的访问权限和当前进程的属主决定。
  21. 共享内存的访问权限类似于文件的访问权限。

3. shmdt

  1. 将共享内存从当前进程中分离。
  2. int shmdt(const void *shm_addr);
  3. shm_addr: shmat返回的地址指针。
  4.  
  5. 成功时,返回0
  6. 失败时,返回-.
  7.  
  8. NOTE:
  9. 共享内存分离并未删除它,
  10. 只是使得该共享内存对当前进程不再可用。

4. shmctl

  1. 共享内存的控制函数
  2. int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
  3. shmid_ds结构至少包含以下成员:
  4. struct shmid_ds {
  5. uid_t shm_perm.uid;
  6. uid_t shm_perm.gid;
  7. mode_t shm_perm.mode;
  8. }
  9.  
  10. 参数:
  11. shm_id : shmget返回的共享内存标识符。
  12. command: 是要采取的动作,
  13. 它可以取3个值:
  14.  
  15. IPC_STAT shmid_ds结构中的数据设置为共享内存的当前关联值
  16. IPC_SET 如果进程有足够的权限,
  17. 就把共享内存的当前关联值设置为shmid_ds结构中给出的值
  18. IPC_RMID 删除共享内存段
  19.  
  20. buf : 是一个指针,
  21. 包含共享内存模式和访问权限的结构。
  22.  
  23. 返回值:
  24. 成功时,返回0
  25. 失败时,返回-.

(完)

共享内存mmap学习 及与 shmxxx操作的区别的更多相关文章

  1. linux下共享内存mmap和DMA(直接访问内存)的使用 【转】

    转自:http://blog.chinaunix.net/uid-7374279-id-4413316.html 介绍Linux内存管理和内存映射的奥秘.同时讲述设备驱动程序是如何使用“直接内存访问” ...

  2. 共享内存:mmap函数实现

    内存映射的应用: 以页面为单位,将一个普通文件映射到内存中,通常在须要对文件进行频繁读写时使用,这样用内存读写代替I/O读写,以获得较高的性能; 将特殊文件进行匿名内存映射,能够为关联进程提供共享内存 ...

  3. 【Linux 应用编程】进程管理 - 进程间通信IPC之共享内存 mmap

    IPC(InterProcess Communication,进程间通信)是进程中的重要概念.Linux 进程之间常用的通信方式有: 文件:简单,低效,需要代码控制同步 管道:使用简单,默认阻塞 匿名 ...

  4. linux 进程间通信 共享内存 mmap

    共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式.两个不同进程A.B共享内存的意思是,同一块物理内存被映射到进程A.B各自的进程地址空间.进程A可以即时看到进程B对共享内存中数据的更新,反 ...

  5. VC++ 共享内存读写操作

    此解决方案含两个工程文件,一个是写操作工程文件,即把任意字符串写入创建的共享内存里,另外一个读操作工程文件,则是读取共享内存里的数据,从而实现了进程之间的共享内存读写操作. 源码下载

  6. Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6939890 在Android系统中,针对移动设 ...

  7. 阐述linux IPC(五岁以下儿童):system V共享内存

    [版权声明:尊重原创.转载请保留源:blog.csdn.net/shallnet 要么 .../gentleliu,文章学习交流,不用于商业用途]         system V共享内存和posix ...

  8. Linux 基于IPC机制实现进程间的共享内存处理

    今天学习了相关于IPC(InterProcess Communication ,进程间通信)的相关知识.就做个笔记,一来让大家检查一下我的理解方面是不是有错误,二来也为了能让更多的博友们了解到相关的知 ...

  9. linux网络编程之system v共享内存

    接着上次的共享内存继续学习,这次主要是学习system v共享内存的使用,下面继续: 跟消息队列一样,共享内存也是有自己的数据结构的,system v共享内存也是随内核持续的,也就是说当最后一个访问内 ...

随机推荐

  1. Java面试题之HashSet 的实现原理?

    HashSet 的实现原理?首先,我们需要知道它是Set的一个实现,所以保证了当中没有重复的元素.一方面Set中最重要的一个操作就是查找.而且通常我们会选择 HashSet来实现,因为它专门对快速查找 ...

  2. docker 新手入门 (阿里镜像仓库的使用)

    创建镜像仓库后的步骤是:   https://help.aliyun.com/document_detail/60743.html?spm=a2c4g.11186623.6.546.79be52f3y ...

  3. uva11925 Generating Permutations

    逆序做,逆序输出 紫书上的描述有点问题 感觉很经典 ans.push_back(2); a.insert(a.begin(),a[n-1]); a.erase(a.end()-1); a.push_b ...

  4. k8s集群之Docker安装镜像加速器配置与k8s容器网络

    安装Docker 参考:https://www.cnblogs.com/rdchenxi/p/10381631.html 加速器配置 参考:https://www.cnblogs.com/rdchen ...

  5. roi pooling层

    roi pooling是先进行roi projection(即映射)然后再池化 映射是把用来训练的图片的roi映射到最后一层特征层(即卷积层).方法其实很简单,图片经过特征提取后,到最后一层卷积层时, ...

  6. css--css选择器,伪类

    前戏 前面我们说过CSS规则由选择器和声明组成,我们要给标签设置属性,那我们就要找到对应的标签,CSS选择器可以帮我们找到我们需要的标签 css选择器有: 标签选择器 类选择器 ID选择器 全局选择器 ...

  7. ios之AFN

    https://github.com/AFNetworking/AFNetworking 与asi-http-request功能类似的网络库,不过是基于NSURLConnection 和 NSOper ...

  8. MySQL索引之博客荐读

    推荐博客: 寒江独钓. 浅谈算法和数据结构: 十 平衡查找树之B树 张洋. MySQL索引背后的数据结构及算法原理 漫画算法:什么是 B+ 树? B树和B+树的插入.删除图文详解 Jeremy Col ...

  9. Ubuntu 和 centos7 服务的启动

    Ubuntu 下: /etc/init.d/nginx  start | stop | reload Centos7下: service nginx start | stop | reload

  10. laravel知识点备忘

    1.连表查询:select * from goods left join shop on goods.shopid=shop.shopid; DB::table('goods') ->leftJ ...