课程实践报告书 课程名称: 题 操作系统原理 目: 进程通信-共享内存 学生姓名: 专 班 学 业: 计算机科学与技术(网络方向) 别: 计科本 113 班 号: 1104402308 指导老师: 日 期: 2013 年 06 月 25 日 目录 一、基本要求.......................................................................................................... 2 二、流程图分析...................................................................................................... 3 三、共享内存描述和使用.................................................................................... 10 3.1 共享内存的概述..................................................................................... 10 3.2 共享内存的原理..................................................................................... 11 3.3 共享内存的分配..................................................................................... 12 3.4 共享内存的访问.................................................................................... 13 3.5 共享内存的应用..................................................................................... 13 3.6 共享内存的意义..................................................................................... 14 四、实验构思........................................................................................................ 14 4.1 main()的使用........................................................................................ 14 4.2 shmget()调用........................................................................................ 16 4.3 fork()的调用........................................................................................ 16 4.4 子进程调用 shmat()............................................................................. 17 4.5 子进程调用 shmdt().............................................................................. 17 4.6 父进程调用 shmctl().......................................................................... 17 4.7 父进程调用 shmat(),shmdt(),shmctl()............................................ 18 五、实验的调试与测试........................................................................................ 18 六、实验结果........................................................................................................ 20 七、源程序............................................................................................................ 21 八、实验感受........................................................................................................ 23 九、参考文献........................................................................................................ 24 一、基本要求 1.1 实验题目:进程通信共享内存 1.2 实践目的:用代码实现进程通信共享内存 1.3 实践内容:用 C 语言代码创建进程,实现进程通信共享 内存(父进程和子进程通过共享内存实现信息的交流) 1.4 实验环境:linux 操作系统及 gcc 工具 二、流程图分析 图 1-1 如图 1-1 首先父进程调用 shmget()函数建立一个共 享内存,该函数返回一内存的标识符。 图 1-2 如图 1-2 父进程调用 fork()产生一个子进程 图 1-3 如图 1-3 子进程调用 shmat()函数将该共享内存连接 到自己的虚存空间中 图 1-4 如图 1-4 写完数据后,子进程调用 shmdt()函数断开 与该进程的连接 如图 1-5 如图 1-5 父进程调用 shmctl()函数得到关于这块共 享内存的相关信息,并打印出来 图 1-6 如图 1-6 父进程调用 shmat()函数将这块共享内存连 接到自己的虚存空间 图 1-7 如图 1-8 父进程调用 shmdt()函数断开与该共享内存的 连接 图 1-8 如图 1-8 父进程调用 shmctl()函数, 销毁该共享进程。 三、共享内存描述和使用 3.1 共享内存的概述 针对消息缓冲需要占用 CPU 进行消息复制的缺点,操作系统提 供了一种进程间直接进行数据交换的通信方式——共享内存。 顾名思 义, 这种通信方式允许多个进程共享同一块物理内存空间来实现进程 之间的信息交换,其特点是没有中间环节,直接将共享的内存页面通 过附接,映射到相互通信的进程各自的虚拟地址空间中,从而使多个 进程可以直接访问同一个物理内存页面, 如同访问自己的私有空间一 样(但实质上不是私有的而是共享的)。因此这种进程间通信方式是 在同一个计算机系统中的诸进程间实现通信的最快捷的方法, 而它的 局限性也在于此,即共享内存的诸进程必须共处同一个计算机系统, 有物理内存可以共享才行。 3.2 共享内存的原理 共享内存是由 IPC 为一个进程所创建并且出现在这个进程的地 址空间中的一段特殊的地址序列。 其他的进程可以将同样的共享内存 段关联到他们自己的地址空间中。 所有的进程都可以访问这段内存地 址,就如同这段内存是由 malloc 所分配的。如果一个进程写入共享 内存, 这些改变立即就可以为访问相同共享内存的其他进程所见。 就 其自身而言,共享内存并没有提供任何共享方法。并没有自动的方法 来阻止在第一个进程完成写入共享内存之前第二个进程开始读取共 享内存。 3.3 共享内存的分配 要使用一块共享内存,进程必须首先分配它。随后需要访问这个 共享内存块的每一个进程都必须将这个共享内存绑定到自己的地址 空间中。当完成通信之后,所有进程都将脱离共享内存,并且由一个 进程释放该共享内存块。 尽管每个进程都有自己的内存地址, 不同的进程可以同时将同一 个内存页面映射到自己的地址空间中,从而达到共享内存的目的。 分配一个新的共享内存块会创建新的内存页面。 因为所有进程都 希望共享对同一块内存的访问, 只应由一个进程创建一块新的共享内 存。再次分配一块已经存在的内存块不会创建新的页面,而只是会返 回一个标识该内存块的标识符。一个进程如需使用这个共享内存块, 则首先需要将它绑定到自己的地址空间中。 这样会创建一个从进程本 身虚拟地址到共享页面的映射关系。当对共享内存的使用结束之后, 这个映射关系将被删除。 当再也没有进程需要使用这个共享内存块的 时候,必须有一个(且只能是一个)进程负责释放这个被共享的内存 页面。 所有共享内存块的大小都必须是系统页面大小的整数倍。 系统页 面大小指的是系统中单个内存页面包含的字节数。进程通过调用 shmget 来分配一个共享内存块。 该函数的第二个参数指定了所申请的内存块的大小。 因为这些内 存块是以页面为单位进行分配的, 实际分配的内存块大小将被扩大到 页面大小的整数倍。 3.4 共享内存的访问 要让一个进程获取对一块共享内存的访问, 这个进程必须先调用 shmat(SHared Memory Attach,绑定到共享内存)。将 shmget 返 回的共享内存标识符 SHMID 传递给这个函数作为第一个参数。该函 数的第二个参数是一个指针, 指向您希望用于映射该共享内存块的进 程内存地址;如果您指定 NULL 则 Linux 会自动选择一个合适的地址 用于映射。 3.5 共享内存的应用 共享内存的通信方式是通过将可以共享的内存缓冲区直接附加 到进程的虚拟地址空间中来实现的,因此,这些进程之间的读写操作 的同步问题操作系统无法实现,必须由诸共享该内存的进程去控制。 另外,由于内存实体存在于计算机系统中,所以只能由处于同一个计 算机系统中的诸进程共享。以上两点是共享内存通信的缺点,但是它 提供了诸进程直接读写信息,无须复制,因而方便快捷的进程间通信 方式,适用于信息量大且操作频繁的场合。 3.6 共享内存的意义 共享内存是进程间通信中最简单的方式之一。 共享内存允许两个 或更多进程访问同一块内存, 就如同 malloc() 函数向不同进程返回 了指向同一个物理内存区域的指针。 当一个进程改变了这块地址中的 内容的时候,其它进程都会察觉到这个更改。 所有进程共享同一块内存, 共享内存在各种进程间通信方式中具 有最高的效率。 访问共享内存区域和访问进程独有的内存区域一样快, 并不需要通过系统调用或者其它需要切入内核的过程来完成。 同时它 也避免了对数据的各种不必要的复制。 四、实验构思 4.1 main()的使用 int main() { int shmid; char *shmaddr; strut shmid_ds buf; shmid=shmget(KEY,SIZE,IPC_CREAT | 0600); if(shmid==-1) { printf("create share memory failed:%s",strerror(errno)); return 0; } if(fork()==0) { sleep(2); shmaddr=(char *)shmat(shmid,NULL,0); if(shmaddr==(void*)-1) { printf("connect failed:%s",strerror(errno)); return 0; } strcpy(shmaddr,"hello,this is shared data.\n"); shmdt(shmaddr); exit(0); }else { wait(0); shmctl(shmid,IPC_STAT,&buf); printf("size printf("process printf("process id id of of of the the the share last last memory:shm_segsz=%dbytes\n",buf.shm_segsz); operator:shm_lpid=%d\n",buf.shm_cpid); operator:shm_lpid+%d\n",buf.shm_lpid); shmaddr=(char *)shmat(shmid,NULL,0); if(shmaddr==(void *)-1) { printf("connectthe share memory to the share memory failed:%s",strerror(errno)); return 0; } printf("print the content of the share memory:"); printf("%s\n",shmaddr); shmdt(shmaddr); shmctl(shmid,IPC_RMID,NULL); } } 4.2 shmget()调用 首先调用 shmget()函数建立一块共享内存,大小为 1024 个字节, shmid=shmget(KEY,SIZE,IPC_CREAT | 0600)建立共享内存,此函数 调用用于创建一个新的共享内存段或存取一个已存在的共享内存段 。 函数调用成功返回共享内存段的标识符 , 否则返回一 1 值。 s h mg e t 的内部实现包含了许多重要的 S y s t e m V 共享内存机制; s h ma t 在把共享内存区域映射到进程空间时 , 并不真正改变进程的页表 。 当进程第一次访 问内存映射区域访问时, 会 因为没有物理页表 的 分配而导致一个缺页异常, 然后 内核再根据相应 的存储管理机制 为共享内存映射区域分配相应的页表。 4.3 fork()的调用 调用 fork()产生一个子进程(生产者进程)。子进程调用 shmat() 函数将该共享内存连接(attach)到自己的虚存空间,即可通过普通 的内存写操作(例如 strcpy 等),在该共享内存写入数据。 4.4 子进程调用 shmat() shmaddr=(char *)shmat(shmid,NULL,0) 系统自动选择一个地址 连接, s h ma t ( ) 可以创建一个共享内存区,或者获得已创建的共享内 存区的标识符后,将共享内存段映射到进程的内存空间。返回共享内 存段的地址, 否则返 回一 1 值。 4.5 子进程调用 shmdt() 写完数据生,子进程调用 shmdt(shmaddr)断开共享,此函数调用 可以将映射到进程的共享内存段撤消。函数调用成功返回 0 值, 否 则返回一 1 。 一个共享内存与一个进程分离时 . 共享内存段的 s h m a r r a y 结构中的共享计数减 1 ,直至计数为 0 ,系统才真正删除 这个共亨内存页面。 4.6 父进程调用 shmctl() 父 进 程 sleep, 直 到 子 进 程 完 成 上 述 操 作 。 shmctl(shmid,IPC_RMID,NULL)取得共享内存的相关信息,并打印出 来 s h mct l 可以用来查询一些共享内存的使用情况和进行一些控制 操作。 函数调用成功后返回 0 值, 否则返回一 1 值。 比如: s h mc t l ( s h m i d , I P C RMI D, 0 ) 将删除 s h m i d 指示的共享内存。 4.7 父进程调用 shmat(),shmdt(),shmctl() 父进程调用 shmat()函数将这块共享内存连接到自己的虚存空间, 即可通过普通的内存读操作(例如 printft 等),将该共享内存中的字 符串读出来。 读完数据后,父进程调用 shmctl()函数,销毁断开与该共享内 存的连接。 最后父进程调用 shmectl()函数,销毁该共享内存。 五、实验的调试与测试 代码编辑如下图所示 在 linux 操作系统下,打开终端,使用 vi 工具编写代码 编写如下图 5-1,图 5-2,图 5-3 代码 图 5-1 图 5-2 图 5-3 使用 gcc –o share share.c 编译代码 六、实验结果 运行./share 结果如下图 七、源程序 #include #include #include #include #include #include #define KEY 1234 #define SIZE 1024 int main() { int shmid; char *shmaddr; struct shmid_ds buf; shmid=shmget(KEY,SIZE,IPC_CREAT | 0600); if(shmid==-1) { printf("create share memory failed:%s",strerror(errno)); return 0; } if(fork()==0) { sleep(2); shmaddr=(char *)shmat(shmid,NULL,0); if(shmaddr==(void*)-1) { printf("connect to the share memory failed:%s",strerror(errno)); return 0; } strcpy(shmaddr,"hello,this is shared data.\n"); shmdt(shmaddr); exit(0); }else { wait(0); shmctl(shmid,IPC_STAT,&buf); printf("size of the share memory:shm_segsz=%dbytes\n",buf.shm_segsz); printf("process id of the last operator:shm_lpid=%d\n",buf.shm_cpid); printf("process id of the last operator:shm_lpid+%d\n",buf.shm_lpid); shmaddr=(char *)shmat(shmid,NULL,0); if(shmaddr==(void *)-1) { printf("connect the share memory failed:%s",strerror(errno)); return 0; } printf("print the content of the share memory:"); printf("%s\n",shmaddr); shmdt(shmaddr); shmctl(shmid,IPC_RMID,NULL); } } 八、实验感受 通过本次实验,我明白了父进程与子进程的共享原理,同时我还 明白了如何实现父进程程子进程通过共享实现信息的交换, 通过对试 验的操作,我们对课本上的知识得到了巩固和提高,对进程通信和内 存共享等功能有了较全面的理解。 这次课程实践充分锻炼了我的动手 能力,思维能力,设计能力,在这次课程实践中,我主动查询资料, 询问同学。通过本次的课程实践,我对共享内存有关的知识有了进一 步的了解,刚刚开始我并不知道如何去完成这次的课程实践,但通过 我去网上查询有关的资料, 我最终知道该从哪里下手去写这篇课程实 践。通过本次的课程实践,我知道了自己身上的不足和自己知识的欠 缺。本次课程实践,我不断地在 linux 系统中调试代码,花了较多的 时间, 最终成功的把代码调试好, 心中充满着喜愉, 通过本课程实践, 我增加了许多的知识,对共享内存的原理,我比以前有了更进一步的 了解。在本次的课程实践中,在调试代码过程中,我发现有较多的错 误,这些错误的产生都是因为我对知识的认识不够深入而产生的。 九、参考文献 1、汤小丹,梁红兵编著·《计算机操作系统》(第三版)·西安电子科技大 学出版社,2007 2、张尧学,史美林,张高编著·《计算机操作系统教程》(第 3 版)·清 华大学出版社,2006 3、、严蔚敏,吴伟民编著·《数据结构》(C 语言版)·清华大学出版社, 2007 4、《计算机操作系统(修订版)》汤子瀛 西安电子科技大学出版社 5、《操作系统考研辅导教程 (计算机专业研究生入学考试全真题解 ) 》电子 科技大学出版社