




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区。在/proc/sys/kernel/目录下,记录着共享内存的一些限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区标识符数shmmni等,可以手工对其调整,但不推荐这样做。一、应用共享内存的使用,主要有以下几个API:ftok()、shmget()、shmat()、shmdt()及shmctl()。1)用ftok()函数获得一个ID号.应用说明:在IPC中,我们经常用用key_t的值来创建或者打开信号量,共享内存和消息队列。函数原型:key_t ftok(const char *pathname, int proj_id);Keys:1)pathname一定要在系统中存在并且进程能够访问的3)proj_id是一个1255之间的一个整数值,典型的值是一个ASCII值。当成功执行的时候,一个key_t值将会被返回,否则1被返回。我们可以使用strerror(errno)来确定具体的错误信息。考虑到应用系统可能在不同的主机上应用,可以直接定义一个key,而不用ftok获得:#define IPCKEY 0x3443782)shmget()用来开辟/指向一块共享内存的函数应用说明:shmget()用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。函数原型:int shmget(key_t key, size_t size, int shmflg);key_t key 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。如果两个进程没有任何关系,所以就用ftok()算出来一个标识符(或者自己定义一个)使用了。int size 是这块内存的大小int flag 是这块内存的模式(mode)以及权限标识。模式可取如下值:IPC_CREAT 新建(如果已创建则返回目前共享内存的id)IPC_EXCL 与IPC_CREAT结合使用,如果已创建则则返回错误然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。如: IPC_CREAT | IPC_EXCL | 0640例子中的0666为权限标识,4/2/1 分别表示读/写/执行3种权限,第一个0是UID,第一个6(4+2)表示拥有者的权限,第二个4表示同组权限,第3个0表示他人的权限。这个函数成功时返回共享内存的ID,失败时返回-1。关于这个函数,要多说两句。创建共享内存时,shmflg参数至少需要 IPC_CREAT | 权限标识,如果只有IPC_CREAT 则申请的地址都是k=0xffffffff,不能使用;获取已创建的共享内存时,shmflg不要用IPC_CREAT(只能用创建共享内存时的权限标识,如0640),否则在某些情况下,比如用ipcrm删除共享内存后,用该函数并用IPC_CREAT参数获取一次共享内存(当然,获取失败),则即使再次创建共享内存也不能成功,此时必须更改key来重建共享内存。3) shmat()将这个内存区映射到本进程的虚拟地址空间。函数原型:void *shmat( int shmid , char *shmaddr , int shmflag );shmat()是用来允许本进程访问一块共享内存的函数。int shmid是那块共享内存的ID。char *shmaddr是共享内存的起始地址,如果shmaddr为0,内核会把共享内存映像到调用进程的地址空间中选定位置;如果shmaddr不为0,内核会把共享内存映像到shmaddr指定的位置。所以一般把shmaddr设为0。int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式成功时,这个函数返回共享内存的起始地址。失败时返回-1。4) shmdt()函数删除本进程对这块内存的使用,shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。函数原型:int shmdt( char *shmaddr );参数char *shmaddr是那块共享内存的起始地址。成功时返回0。失败时返回-1。5) shmctl() 控制对这块共享内存的使用函数原型:int shmctl( int shmid , int cmd , struct shmid_ds *buf );int shmid是共享内存的ID。int cmd是控制命令,可取值如下: IPC_STAT 得到共享内存的状态 IPC_SET 改变共享内存的状态 IPC_RMID 删除共享内存struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。返回值: 成功:0 失败:-1示例程序:#include #include #include #include #include #define IPCKEY 0x366378typedef structchar agen10;unsigned char file_no; st_setting;int main(int argc, char* argv) int shm_id; key_t key; st_setting *p_setting; /首先检查共享内存是否存在,存在则先删除 shm_id = shmget(IPCKEY ,1028,0640); if(shm_id != -1) p_setting = (st_setting*)shmat(shm_id,NULL,0); if ( p_setting != (void *)-1) shmdt(p_setting); shmctl(shm_id,IPC_RMID,0) ; shm_id=shmget(IPCKEY,1028,0640|IPC_CREAT|IPC_EXCL); if(shm_id=-1) printf(shmget errorn); return -1; /将这块共享内存区附加到自己的内存段 p_setting=(st_setting*)shmat(shm_id,NULL,0); strncpy(p_setting-agen,jinyh,10); printf( agen:%sn,p_setting-agen ); p_setting-file_no = 1; printf( file_no:%dn,p_setting-file_no ); system(ipcs -m);/此时可看到有进程关联到共享内存的信息,nattch为1 /将这块共享内存区从自己的内存段删除出去 if(shmdt(p_setting) = -1) perror( detach error ); system(ipcs -m);/此时可看到有进程关联到共享内存的信息,nattch为0 /删除共享内存 if (shmctl( shm_id , IPC_RMID , NULL ) = -1) perror( delete error ); /exit(0);注意:在使用共享内存,结束程序退出后。如果你没在程序中用shmctl()删除共享内存的话,一定要在命令行下用ipcrm命令删除这块共享内存。你要是不管的话,它就一直在那儿放着了。简单解释一下ipcs命令和ipcrm命令。取得ipc信息:ipcs -m|-q|-s-m 输出有关共享内存(shared memory)的信息-q 输出有关信息队列(message queue)的信息-s 输出有关“遮断器”(semaphore)的信息%ipcs -m删除ipcipcrm -m|-q|-s shm_id%ipcrm -m 105二、陷阱(参考/developerworks/cn/aix/library/au-cn-sharemem/)1)ftok陷阱采用ftok来生成key的情况下,如果ftok的参数pathname指定文件被删除后重建,则文件系统会赋予这个同名文件(或目录)新的i节点信息,于是这些进程所调用的ftok虽然都能正常返回,但得到的键值却并不能保证相同。2)3. AIX中shmat的问题AIX系统中,System V各类进程间通信机制在使用中均存在限制。区别于其它UNIX操作系统对IPC机制的资源配置方式,AIX使用了不同的方法;在AIX中定义了 IPC 机制的上限, 且是不可配置的。就共享内存机制而言,在4.2.1及以上版本的AIX系统上,存在下列限制:对于64位进程,同一进程可连接最多268435456个共享内存段;对于32位进程,同一进程可连接最多11个共享内存段,除非使用扩展的shmat;上述限制对于64位应用不会带来麻烦,因为可供连接的数量已经足够大了;但对于32位应用,却很容易带来意外的问题,因为最大的连接数量只有11个。下面的例程test02.c演示了这个问题,为了精简代码,它反复连接的是同一个共享内存对象;实际上,无论所连接的共享内存对象是否相同,该限制制约的是连接次数:#include #include #include #include #include #define MAX_ATTACH_NUM 15void main(int argc, char* argv) key_t mem_key; long mem_id; void* mem_addrMAX_ATTACH_NUM; int i; if ( ( mem_key = ftok(/tmp/mykeyfile, 1) ) = (key_t)(-1) ) printf(Failed to generate shared memory access key, ERRNO=%dn, errno); goto MOD_EXIT; if ( ( mem_id = shmget(mem_key, 256, IPC_CREAT) ) = (-1) ) printf(Failed to obtain shared memory ID, ERRNO=%dn, errno); goto MOD_EXIT; for ( i=1; i SHMMAX */struct vm_area_struct *attaches; /* descriptors for attaches */;其中:shm_pages是该共享内存对象的页表,每个共享内存对象一个,它描述了如何把该共享内存区域映射到进程的地址空间的信息。shm_npages是该共享内存区域的大小,以页为单位。shmid_ds是一个数据结构,它描述了这个共享内存区的认证信息,字节大小,最后一次粘附时间、分离时间、改变时间,创建该共享区域的进程,最后一次 对它操作的进程,当前有多少个进程在使用它等信息。其定义如下: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_pid_t shm_cpid; /* pid of creator */_kernel_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描述被共享的物理内存对象所映射的各进程的虚拟内存区域。每一个希望共享这块内存的进程都必须通过系统调用将其粘附(attach)到它 的虚拟内存中。这一过程将为该进程创建了一个新的描述这块共享内存的vm_area_struct数据结构。进程可以选择共享内存在它的虚拟地址空间的位 置,也可以让Linux为它选择一块足够的空闲区域。这个新的vm_area_struct结构除了要连接到进程的内存结构mm中以外,还被连接到共享内存数据结构shmid_kernel的一个链表中,该 结构中的attaches指针指向该链表。vm_area_struct数据结构中专门提供了两个指针:vm_next_shared和 vm_prev_shared,用于连接该共享区域在使用它的各进程中所对应的vm_area_struct数据结构。其实,虚拟内存并没有在粘附的时候 创建,而要等到第一个进程试图访问它的时候才创建。图 System V IPC 机制 - 共享内存Linux为共享内存提供了四种操作。1. 共享内存对象的创建或获得。与其它两种IPC机制一样,进程在使用共享内存区域以前,必须通过系统调用sys_ipc (call值为SHMGET)创建一个键值为key的共享内存对象,或获得已经存在的键值为key的某共享内存对象的引用标识符。以后对共享内存对象的访 问都通过该引用标识符进行。对共享内存对象的创建或获得由函数sys_shmget完成,其定义如下:int sys_shmget (key_t key, int size, int shmflg)这里key是表示该共享内存对象的键值,size是该共享内存区域的大小(以字节为单位),shmflg是标志(对该共享内存对象的特殊要求)。它所做的工作如下:1) 如果key = IPC_PRIVATE,则创建一个新的共享内存对象。* 算出size对应的页数,检查其合法性。* 搜索向量表shm_segs,为新创建的共享内存对象找一个空位置。* 申请一块内存用于建立shmid_kernel数据结构,注意这里申请的内存区域大小不包括真正的共享内存区,实际上,要等到第一个进程试图访问它的时候 才真正创建共享内存区。* 根据该共享内存区所占用的页数,为其申请一块空间用于建立页表(每页4个字节),将页表清0。* 填写shmid_kernel数据结构,将其加入到向量表shm_segs中为其找到的空位置。* 返回该共享内存对象的引用标识符。2) 在向量表shm_segs中查找键值为key的共享内存对象,结果有三:* 如果没有找到,而且在操作标志shmflg中没有指明要创建新共享内存,则错误返回,否则创建一个新的共享内存对象。* 如果找到了,但该次操作要求必须创建一个键值为key的新对象,那么错误返回。* 否则,合法性、认证检查,如有错,则错误返回;否则,返回该内存对象的引用标识符。共享内存对象的创建者可以控制对于这块内存的访问权限和它的key是公开还是私有。如果有足够的权限,它也可以把共享内存锁定在物理内存中。参见include/linux/shm.h2. 粘附。在创建或获得某个共享内存区域的引用标识符后,还必须将共享内存区域映射(粘附)到进程的虚拟地址空间,然后才能使用该共享内存区域。系统调用 sys_ipc(call值为SHMAT)用于共享内存区到进程虚拟地址空间的映射,而真正完成粘附动作的是函数sys_shmat,其定义如下:int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)其中:shmid是共享内存对象的引用标识符;shmaddr该共享内存区域在进程的虚拟地址空间对应的虚拟地址;shmflg是映射标志;raddr是实际映射的虚拟空间地址。该函数所做的工作如下:1) 根据shmid找到共享内存对象。2) 如果shmaddr为0,即用户没有指定该共享内存区域在它的虚拟空间中的位置,则由系统在进程的虚拟地址空间中为其找一块区域(从1G开始);否则,就 用shmaddr作为映射的虚拟地址。3) 检查虚拟地址的合法性(不能超过进程的最大虚拟空间大小3G,不能太接近堆栈栈顶)。4) 认证检查。5) 申请一块内存用于建立数据结构vm_area_struct,填写该结构。6) 检查该内存区域,将其加入到进程的mm结构和该共享内存对象的vm_area_struct队列中。共享内存的粘附只是创建一个vm_area_struct数据结构,并将其加入到相应的队列中,此时并没有创建真正的共享内存页。当进程第一次访问共享虚拟内存的某页时,因为所有的共享内存页还都没有分配,所以会发生一个page fault异常。当Linux处理这个page fault的时候,它找到发生异常的虚拟地址所在的vm_area_struct数据结构。在该数据结构中包含有这类共享虚拟内存的一组处理例程,其中的 nopage操作用来处理虚拟页对应的物理页不存在的情况。对共享内存,该操作是shm_nopage(定义在ipc/shm.c中)。该操作在描述这个 共享内存的shmid_kernel数据结构的页表shm_pages中查找发生page fault异常的虚拟地址所对应的页表条目,看共享页是否存在(页表条目为0,表示共享页是第一次使用)。如果不存在,它就分配一个物理页,并为它创建一 个页表条目。这个条目不但进入当前进程的页表,同时也存到shmid_kernel数据结构的页表shm_pages中。当下一个进程试图访问这块内存并得到一个page fault的时候,经过同样的路径,也会走到函数shm_nopage。此时,该函数查看shmid_kernel数据结构的页表shm_pages时, 发现共享页已经存在,它只需把这里的页表项填到进程页表的相应位置即可,而不需要重新创建物理页。所以,是第一个访问共享内存页的进程使得这一页被创建, 而随后访问它的其它进程仅把此页加到它们的虚拟地址空间。3. 分离。当进程不再需要共享虚拟内存的时候,它们与之分离(detach)。只要仍旧有其它进程在使用这块内存,这种分离就只会影响当前的进程,而不会影响 其它进程。当前进程的vm_area_struct数据结构被从shmid_ds中删除,并被释放。当前进程的页表也被更新,共享内存对应的虚拟内存页被 标记为无效。当共享这块内存的最后一个进程与之分离时,共享内存页被释放,同时,这块共享内存的shmid_kernel数据结构也被释放。系统调用sys_ipc(call值为SHMDT)用于共享内存区与进程虚拟地址空间的分离,而真正完成分离动作的是函数sys_shmdt,其定义如 下:int sys_shmdt (char *shmaddr)其中shmaddr是进程要分离的共享页的开始虚拟地址。该函数搜索进程的内存结构中的所有vm_area_struct数据结构,找到地址shmaddr对应的一个,调用函数do_munmap将其释放。在函数do_munmap中,将要释放的vm_area_struct数据结构从进程的虚拟内存中摘下,清除它在进程页表中对应的页表项(可能占多个页表 项),调用该共享内存数据结构vm_area_struct的操作例程中的close操作(此处为shm_close)做进一步的处理。在函数shm_close(定义在ipc/shm.c中)中,找到该共享内存对象在向量表shm_segs中的索引,从而找到该共享内存对象,将该共享内 存在当前进程中对应的vm_area_struct数据结构从对象的共享内存区域链表(由vm_next_share和vm_pprev_share指针 连接)中摘下。如果目前与该共享内存对象粘附的进程数变成了0,则释放共享内存页,释放共享内存页表,释放该对象的shmid_kernel数据结构,将 向量表shm_segs中该共享内存对象所占用的项改为IPC_UNUSED。如果共享的虚拟内存没有被锁定在物理内存中,分离会更加复杂。因为在这种情况下,共享内存的页可能在系统大量使用内存的时候被交换到系统的交换磁盘。为了 避免这种情况,可以通过下面的控制操作,将某共享内存页锁定在物理内存不允许向外交换。共享内存的换出和换入,已在第3章中讨论。4. 控制。Linux在共享内存上实现的第四种操作是共享内存的控制(call值为SHMCTL的sys_ipc调用),它由函数sys_shmctl实现。 控制操作包括获得共享内存对象的状态,设置共享内
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 预应力工程施工现场安全保障措施
- 2025国考阜新市金融监管岗位申论模拟题及答案
- 2025国考大连市劳动监察岗位行测必刷题及答案
- 四川省中学篮球课堂教学质量评价指标体系构建及其提升策略研究
- 难点详解人教版八年级上册物理声现象《声音的产生与传播》章节训练试题(含答案解析)
- 混凝土回弹检测实施方案
- 达标测试人教版八年级上册物理声现象《声音的特性》单元测试试题(含答案解析)
- 2025国考乌兰察布市气象服务岗位申论题库含答案
- 2025国考阿拉善盟巡视巡察岗位申论模拟题及答案
- 建筑预应力技术难题与解决方案
- GB/T 191-2025包装储运图形符号标志
- 青协申请书508字
- 2025年大连理工大学专职辅导员招聘考试参考题库及答案解析
- 旋挖桩施工专项方案设计要点
- 人工智能+应急管理智能应急演练评估与改进策略报告
- 人工智能+农业病虫害防治研究报告
- 国际压力性损伤-溃疡预防和治疗临床指南(2025年版)解读课件
- GB 16325-2005干果食品卫生标准
- FZ/T 73001-2016袜子
- 曾奇峰精神分析初级50讲讲义
- 卡尔曼(Kalman)滤波课件
评论
0/150
提交评论