版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Linux 进程间通信 - 共享内存shmget方式(转) 共享内存区域是被多个进程共享的一部分物理内存。如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信。共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。这块共享虚拟内存的页面,出现在每一个共享该页面的进程的页表中。但是它不需要在所有进程的虚拟内存中都有相同的虚拟地址。 图 共享内存映射图 象所有的 System V IPC对象一样,对于共享内存对象的获取是由key控制。内存共享之后,对进程如何
2、使用这块内存就不再做检查。它们必须依赖于其它机制,比如System V的信号灯来同步对于共享内存区域的访问(信号灯如何控制对临界代码的访问另起一篇说话)。 每一个新创建的共享内存对象都用一个shmid_kernel数据结构来表达。系统中所有的shmid_kernel数据结构都保存在shm_segs向量表中,该向量表的每一个元素都是一个指向shmid_kernel数据结构的指针。 shm_segs向量表的定义如下: struct shmid_kernel *shm_segsSHMMNI; SHMMNI为128,表示系统中最多可以有128个共享内存对象。 数据结构shmid_kernel的定义如下
3、: struct shmid_kernel struct shmid_ds u; /* the following are private */ unsigned long shm_npages; /* size of segment (pages) */ unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */ struct vm_area_struct *attaches; /* descriptors for attaches */ ; 其中: shm_pages代表该共享内存对象的所占据的内存页面数组,数组
4、里面的每个元素当然是每个内存页面的起始地址. shm_npages则是该共享内存对象占用内存页面的个数,以页为单位。这个数量当然涵盖了申请空间的最小整数倍. (A new shared memory segment, with size equal to the value of size rounded up to a multiple of PAGE_SIZE) shmid_ds是一个数据结构,它描述了这个共享内存区的认证信息,字节大小,最后一次粘附时间、分离时间、改变时间,创建该共享区域的进程,最后一次对它操作的进程,当前有多少个进程在使用它等信息。 其定义如下: struct shmi
5、d_ds struct ipc_perm shm_perm; /* operation perms */ int shm_segsz; /* size of segment (bytes) */ _kernel_time_t shm_atime; /* last attach time */ _kernel_time_t shm_dtime; /* last detach time */ _kernel_time_t shm_ctime; /* last change time */ _kernel_ipc_pid_t shm_cpid; /* pid of creator */ _kerne
6、l_ipc_pid_t shm_lpid; /* pid of last operator */ unsigned short shm_nattch; /* no. of current attaches */ unsigned short shm_unused; /* compatibility */ void *shm_unused2; /* ditto - used by DIPC */ void *shm_unused3; /* unused */ ; attaches描述被共享的物理内存对象所映射的各进程的虚拟内存区域。每一个希望共享这块内存的进程都必须通过系统调用将其关联(atta
7、ch)到它的虚拟内存中。这一过程将为该进程创建了一个新的描述这块共享内存的vm_area_struct数据结构。创建时可以指定共享内存在它的虚拟地址空间的位置,也可以让Linux自己为它选择一块足够的空闲区域。 这个新的vm_area_struct结构是维系共享内存和使用它的进程之间的关系的,所以除了要关联进程信息外,还要指明这个共享内存数据结构shmid_kernel所在位置; 另外,便于管理这些经常变化的vm_area_struct,所以采取了链表形式组织这些数据结构,链表由attaches指向,同时 vm_area_struct数据结构中专门提供了两个指针:vm_next_shared和
8、 vm_prev_shared,用于连接该共享区域在使用它的各进程中所对应的vm_area_struct数据结构。 图 System V IPC 机制 - 共享内存 Linux为共享内存提供了四种操作。 1. 共享内存对象的创建或获得。与其它两种IPC机制一样,进程在使用共享内存区域以前,必须通过系统调用sys_ipc (call值为SHMGET)创建一个键值为key的共享内存对象,或获得已经存在的键值为key的某共享内存对象的引用标识符。以后对共享内存对象的访问都通过该引用标识符进行。对共享内存对象的创建或获得由函数sys_shmget完成,其定义如下: int sys_shmget (ke
9、y_t key, int size, int shmflg) 这里key是表示该共享内存对象的键值,size是该共享内存区域的大小(以字节为单位),shmflg是标志(对该共享内存对象的特殊要求)。 它所做的工作如下: 1) 如果key = IPC_PRIVATE,则总是会创建一个新的共享内存对象。 但是 (The name choice IPC_PRIVATE was perhaps unfortunate, IPC_NEW would more clearly show its function) * 算出size要占用的页数,检查其合法性。 * 申请一块内存用于建立shmid_kerne
10、l数据结构,注意这里申请的内存区域大小不包括真正的共享内存区,实际上,要等到第一个进程试图访问它的时候才真正创建共享内存区。 * 根据该共享内存区所占用的页数,为其申请一块空间用于建立页表(每页4个字节),将页表清0。 * 搜索向量表shm_segs,为新创建的共享内存对象找一个空位置。 * 填写shmid_kernel数据结构,将其加入到向量表shm_segs中为其找到的 空位置。 * 返回该共享内存对象的引用标识符。 2) 在向量表shm_segs中查找键值为key的共享内存对象,结果有三: * 如果没有找到,而且在操作标志shmflg中没有指明要创建新共享内存,则错误返回,否则创建一个新
11、的共享内存对象。 * 如果找到了,但该次操作要求必须创建一个键值为key的新对象,那么错误返回。 * 否则,合法性、认证检查,如有错,则错误返回;否则,返回该内存对象的引用标识符。 共享内存对象的创建者可以控制对于这块内存的访问权限和它的key是公开还是私有。如果有足够的权限,它也可以把共享内存锁定在物理内存中。 参见include/linux/shm.h 2. 关联。在创建或获得某个共享内存区域的引用标识符后,还必须将共享内存区域映射(粘附)到进程的虚拟地址空间,然后才能使用该共享内存区域。系统调用 sys_ipc(call值为SHMAT)用于共享内存区到进程虚拟地址空间的映射,而真正完成粘
12、附动作的是函数sys_shmat, 其定义如下: #include <sys/types.h> #include <sys/shm.h> void *shmat(int shmid, const void *shmaddr, int shmflg); 其中: shmid是shmget返回的共享内存对象的引用标识符; shmaddr用来指定该共享内存区域在进程的虚拟地址空间对应的虚拟地址; shmflg是映射标志; 返回的是 在进程中的虚拟地址 该函数所做的工作如下: 1) 根据shmid找到共享内存对象。 2) 如果shmaddr为0,即用户没有指定该共享内存区域在它的
13、虚拟空间中的位置,则由系统在进程的虚拟地址空间中为其找一块区域(从1G开始);否则,就用shmaddr作为映射的虚拟地址。 (If shmaddr is NULL, the system chooses a suitable (unused) address a他 which to attach the segment) 3) 检查虚拟地址的合法性(不能超过进程的最大虚拟空间大小3G,不能太接近堆栈栈顶)。 4) 认证检查。 5) 申请一块内存用于建立数据结构vm_area_struct,填写该结构。 6) 检查该内存区域,将其加入到进程的mm结构和该共享内存对象的vm_area_struct
14、队列中。 共享内存的粘附只是创建一个vm_area_struct数据结构,并将其加入到相应的队列中,此时并没有创建真正的共享内存页。 当进程第一次访问共享虚拟内存的某页时,因为所有的共享内存页还都没有分配,所以会发生一个page fault异常。当Linux处理这个page fault的时候,它找到发生异常的虚拟地址所在的vm_area_struct数据结构。在该数据结构中包含有这类共享虚拟内存的一组处理程序,其中的 nopage操作用来处理虚拟页对应的物理页不存在的情况。对共享内存,该操作 是shm_nopage(定义在ipc/shm.c中)。该操作在描述这个共享内存的shmid_kerne
15、l数据结构的页表shm_pages中查找发生page fault异常的虚拟地址所对应的页表条目,看共享页是否存在(页表条目为0,表示共享页是第一次使用)。如果不存在,它就分配一个物理页,并为它创建一个页表条目。这个条目不但进入当前进程的页表,同时也存到shmid_kernel数据结构的页表shm_pages中。 当下一个进程试图访问这块内存并得到一个page fault的时候,经过同样的路径,也会走到函数shm_nopage。此时,该函数查看shmid_kernel数据结构的页表shm_pages时,发现共享页已经存在,它只需把这里的页表项填到进程页表的相应位置即可,而不需要重新创建物理页。所
16、以,是第一个访问共享内存页的进程使得这一页被创建,而随后访问它的其它进程仅把此页加到它们的虚拟地址空间。 3. 分离。当进程不再需要共享虚拟内存的时候,它们与之分离(detach)。只要仍旧有其它进程在使用这块内存,这种分离就只会影响当前的进程,而不会影响其它进程。当前进程的vm_area_struct数据结构被从shmid_ds中删除,并被释放。当前进程的页表也被更新,共享内存对应的虚拟内存页被标记为无效。当共享这块内存的最后一个进程与之分离时,共享内存页被释放,同时,这块共享内存的shmid_kernel数据结构也被释放。 系统调用sys_ipc (call值为SHMDT) 用于共享内存区
17、与进程虚拟地址空间的分离,而真正完成分离动作的是函数 sys_shmdt,其定义如下: int sys_shmdt (char *shmaddr) 其中shmaddr是进程要分离的共享页的开始虚拟地址。 该函数搜索进程的内存结构中的所有vm_area_struct数据结构,找到地址shmaddr对应的一个,调用函数do_munmap将其释放。 在函数do_munmap中,将要释放的vm_area_struct数据结构从进程的虚拟内存中摘下,清除它在进程页表中对应的页表项(可能占多个页表项). 如果共享的虚拟内存没有被锁定在物理内存中,分离会更加复杂。因为在这种情况下,共享内存的页可能在系统大量
18、使用内存的时候被交换到系统的交换磁盘。为了避免这种情况,可以通过下面的控制操作,将某共享内存页锁定在物理内存不允许向外交换。共享内存的换出和换入,已在第3章中讨论。 4. 控制。Linux在共享内存上实现的第四种操作是共享内存的控制(call值为SHMCTL的sys_ipc调用),它由函数sys_shmctl实现。控制操作包括获得共享内存对象的状态,设置共享内存对象的参数(如uid、gid、mode、ctime等),将共享内存对象在内存中锁定和释放(在对象的mode上增加或去除SHM_LOCKED标志), 释放共享内存对象资源等。 共享内存提供了一种快速灵活的机制,它允许进程之间直接共享大量的
19、数据,而无须使用拷贝或系统调用。共享内存的主要局限性是它不能提供同步,如果两个进程企图修改相同的共享内存区域,由于内核不能串行化这些动作,因此写的数据可能任意地互相混合。所以使用共享内存的进程必须设计它们自己的同步协议,如用信号灯等。 以下是使用共享内存机制进行进程间通信的基本操作: 需要包含的头文件: #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> 1.创建共享内存: int shmget(key_t key,int size,int shmflg); 参数说明: key:用
20、来表示新建或者已经存在的共享内存去的关键字。 size:创建共享内存的大小。 shmflg:可以指定的特殊标志。IPC_CREATE,IPC_EXCL以及低九位的权限。 eg: int shmid; shmid=shmget(IPC_PRIVATE,4096,IPC_CREATE|IPC_EXCL|0660); if(shmid=-1) perror("shmget()"); 2.连接共享内存 char *shmat(int shmid,char *shmaddr,int shmflg); 参数说明 shmid:共享内存的关键字 shmaddr:指定共享内存出现在进程内存地
21、址的什么位置,通常我们让内核自己决定一个合适的地址位置,用的时候设为0。 shmflg:制定特殊的标志位。 eg: int shmid; char *shmp; shmp=shmat(shmid,0,0); if(shmp=(char *)(-1) perror("shmat()n"); 3.使用共享内存 在使用共享内存是需要注意的是,为防止内存访问冲突,我们一般与信号量结合使用。 4.分离共享内存:当程序不再需要共享内后,我们需要将共享内存分离以便对其进行释放,分离共享内存的函数原形如下: int shmdt(char *shmaddr); 5. 释放共享内存 int s
22、hmctl(int shmid,int cmd,struct shmid_ds *buf); shmget int shmget(key_t key, size_t size, int flag); key: 标识符的规则 size:共享存储段的字节数 flag:读写的权限 返回值:成功返回共享存储的id,失败返回-1 key_t key - key标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。
23、 在IPC的通信模式下,不管是使用消息队列还是共享内存,甚至是信号量,每个IPC的对象(object)都有唯一的名字,称为“键”(key)。通过“键”,进程能够识别所用的对象。“键”与IPC对象的关系就如同文件名称之于文件,通过文件名,进程能够读写文件内的数据,甚至多个进程能够共用一个文件。而在IPC的通讯模式下,通过“键”的使用也使得一个IPC对象能为多个进程所共用。 Linux系统中的所有表示System V中IPC对象的数据结构都包括一个ipc_perm结构,其中包含有IPC对象的键值,该键用于查找System V中IPC对象的引用标识符。如果不使用“键”,进程将无法存取IPC对象,因为
24、IPC对象并不存在于进程本身使用的内存中。 通常,都希望自己的程序能和其他的程序预先约定一个唯一的键值,但实际上并不是总可能的成行的,因为自己的程序无法为一块共享内存选择一个键值。因此,在此把key设为IPC_PRIVATE,这样,操作系统将忽略键,建立一个新的共享内存,指定一个键值,然后返回这块共享内存IPC标识符ID。而将这个新的共享内存的标识符ID告诉其他进程可以在建立共享内存后通过派生子进程,或写入文件或管道来实现。 int size(单位字节Byte) - size是要建立共享内存的长度。所有的内存分配操作都是以页为单位的。所以如果一段进程只申请一块只有一个字节的内存,内存也会分配整
25、整一页(在i386机器中一页的缺省大小PACE_SIZE=4096字节)这样,新创建的共享内存的大小实际上是从size这个参数调整而来的页面大小。即如果size为1至4096,则实际申请到的共享内存大小为4K(一页);4097到8192,则实际申请到的共享内存大小为8K(两页),依此类推。 int shmflg - shmflg主要和一些标志有关。其中有效的包括IPC_CREAT和IPC_EXCL,它们的功能与open()的O_CREAT和O_EXCL相当。 IPC_CREAT 如果共享内存不存在,则创建一个共享内存,否则打开操作。 IPC_EXCL 只有在共享内存不存在的时候,新的共享内存才
26、建立,否则就产生错误。 如果单独使用IPC_CREAT,shmget()函数要么返回一个已经存在的共享内存的操作符,要么返回一个新建的共享内存的标识符。如果将IPC_CREAT和IPC_EXCL标志一起使用,shmget()将返回一个新建的共享内存的标识符;如果该共享内存已存在,或者返回-1。IPC_EXEL标志本身并没有太大的意义,但是和IPC_CREAT标志一起使用可以用来保证所得的对象是新建的,而不是打开已有的对象。对于用户的读取和写入许可指定SHM_R和SHM_W,(SHM_R>3)和(SHM_W>3)是一组读取和写入许可,而(SHM_R>6)和(SHM_W>6
27、)是全局读取和写入许可。 返回值 - 成功返回共享内存的标识符;不成功返回-1,errno储存错误原因。 EINVAL 参数size小于SHMMIN或大于SHMMAX。 EEXIST 预建立key所致的共享内存,但已经存在。 EIDRM 参数key所致的共享内存已经删除。 ENOSPC 超过了系统允许建立的共享内存的最大值(SHMALL )。 ENOENT 参 数key所指的共享内存不存在,参数shmflg也未设IPC_CREAT位。 EACCES 没有权限。 ENOMEM 核心内存不足。 struct shmid_ds - shmid_ds数据结构表示每个新建的共享内存。当shmget()创
28、建了一块新的共享内存后,返回一个可以用于引用该共享内存的shmid_ds数据结构的标识符。 include/linux/shm.h struct shmid_ds struct ipc_perm shm_perm; /* operation perms */ int shm_segsz; /* size of segment (bytes) */ _kernel_time_t shm_atime; /* last attach time */ _kernel_time_t shm_dtime; /* last detach time */ _kernel_time_t shm_ctime; /* last change time */ _kernel_ipc_pi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 匆匆 听评课记录
- 创意蛋壳画听评课记录
- 《桥》听评课记录表
- 2012年沙盘课程设计
- 部编人教版语文七年级上册第19课《皇帝的新装》市课一等奖教学设计
- 濮阳市范县2024年一级造价工程师《土建计量》预测试卷含解析
- 《斯托克斯定理》课件
- 河南省驻马店市上蔡县2024-2025学年九年级上学期12月月考道德与法治试题(含答案)
- 《激励专题远离贫穷》课件
- 《世界自由经济区》课件
- 2023-2024学年西藏藏族自治区拉萨市小学数学六年级上册期末深度自测试卷
- 中国殡葬网络舆情典型剖析、问题反思与政策导向
- 43 可持续发展的基本内涵
- 油水分离简介及应用
- YY/T 1819-2022牙科学正畸矫治器用膜片
- GB/T 3091-2015低压流体输送用焊接钢管
- GB/T 27692-2011高炉用酸性铁球团矿
- GB/T 16865-1997变形铝、镁及其合金加工制品拉伸试验用试样
- 建筑施工变更流程图
- 整套教学课件《中级财务会计》
- 中国当代文学专题汇集
评论
0/150
提交评论