实验三 进程通信(一)
实验3进程通信(1)

实验3 进程通信(一)UNIX/LINUX系统的进程间通信机构(IPC)允许在任意进程间大批量地交换数据。
本实验的目的是了解和熟悉LINUX支持的信号量机制、管道机制、消息通信机制及共享存储区机制。
一、信号量机制实验目的1、了解什么是信号2、熟悉LINUX系统中进程之间软中断通信的基本原理实验内容1、编写程序:用fork( )创建两个子进程,再用系统调用signal( )让父进程捕捉键盘上来的中断信号(即按^c键);捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:Child process1 is killed by parent!Child process2 is killed by parent!父进程等待两个子进程终止后,输出如下的信息后终止:Parent process is killed!2、分析利用软中断通信实现进程同步的机理实验指导(一)信号1、信号的基本概念每个信号都对应一个正整数常量(称为signal number,即信号编号。
定义在系统头文件<signal.h>中),代表同一用户的诸进程之间传送事先约定的信息的类型,用于通知某进程发生了某异常事件。
每个进程在运行时,都要通过信号机制来检查是否有信号到达。
若有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该事件的处理;处理结束后再返回到原来的断点继续执行。
实质上,信号机制是对中断机制的一种模拟,故在早期的UNIX版本中又把它称为软中断。
信号与中断的相似点:(1)采用了相同的异步通信方式;(2)当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;(3)都在处理完毕后返回到原来的断点;(4)对信号或中断都可进行屏蔽。
信号与中断的区别:(1)中断有优先级,而信号没有优先级,所有的信号都是平等的;(2)信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;(3)中断响应是及时的,而信号响应通常都有较大的时间延迟。
操作系统实验三进程的管道通信

实验三进程的管道通信一、实验目的:(1)加深对进程概念的理解,明确进程和程序的区别;(2)学习进程创建的过程,进一步认识并发执行的实质;(3)分析进程争用资源的现象,学习解决进程互斥的方法;(4)学习解决进程同步的方法;(5)掌握Linux系统进程间通过管道通信的具体实现方法。
二、实验内容及要求:(1)使用系统调用pipe()建立一条管道线,两个子进程分别向管道写一句话(写的内容自己定,但要有该进程的一些信息);(2)父进程从管道中读出来自两个子进程的消息,显示在屏幕上;(3)要求:父进程首先接收子进程p1发来的消息,然后再接收子进程p2发来的消息;(4)两个子进程要并发执行;(5)实现管道的互斥使用。
当一个子进程正在对管道进行写操作时,另一个欲写入管道的子进程必须等待。
使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定;(6)实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。
三、实现:相关的系统调用fork() 用于创一个子进程。
格式:int fork();返回值:在子进程中返回0;在父进程中返回所创建的子进程的ID值;当返回-1时,创建失败。
wait() 常用来控制父进程与子进程的同步。
在父进程中调用wait(),则父进程被阻塞,进入等待队列,等待子进程结束。
当子进程结束时,父进程从wait()返回继续执行原来的程序。
返回值:大于0时,为子进程的ID值;等于-1时,调用失败。
exit() 是进程结束时最常调用的。
格式:void exit( int status); 其中,status为进程结束状态。
pipe() 用于创建一个管道格式:pipe(int fd);其中fd是一个由两个数组元素fd[0]和fd[1]组成的整型数组,fd[0]是管道的读端口,用于从管道读出数据,fd[1]是管道的写端口,用于向管道写入数据。
进程实验-进程间通信(管道、消息、共享内存、软中断)

进程实验3 Linux 进程间通信一、软中断信号的处理,实现同一用户的各进程之间的通信。
●相关的系统调用⏹kill(pid ,sig):发送信号⏹signal(sig, func):指定进程对信号sig的处理行为是调用函数func。
●程序清单#include <unistd.h>#include <stdio.h>#include <signal.h>void waiting();void stop();int wait_mark;main(){int p1,p2;while((p1=fork())==-1);if(p1>0){while((p2=fork())==-1);if(p2>0){ printf("parent\n");/*父进程在此完成某个操作、或接收到用户从键盘输入的特殊按键命令后发出下面的信号。
这里省略。
*/kill(p1,16);kill(p2,17);wait(0);wait(0);printf("parent process id killed! \n");exit(0);}else/* p2==0*/{printf("p2\n");wait_mark=1;signal(17,stop);waiting();printf("child process 2 is killed by parent! \n");exit(0);}}else/*p1==0*/{printf("p1\n");wait_mark=1;signal(16,stop);waiting();printf("child process 1 is kelled by parent! \n");exit(0);}}void waiting(){while(wait_mark!=0);}void stop(){wait_mark=0;}●输入并运行此程序,分析程序的运行结果。
实验三、进程通信(一) ——管道及共享内存

(1)阅读以上父子进程利用管道进行通信的例子(例1),写出程序的运行结果并分析
实验代码:
#include<stdio.h>
main()
{ int x,fd[2];
char buf[30],s[30];
pipe(fd);
while ((x=fork())==-1);
if (x==0)
}
write(fe[1],s,30);
wait(0);
}
运行结果:
(3)阅读例2的程序,运行一次该程序,然后用ipcs命令查看系统中共享存储区的情况,再次执行该程序,再用ipcs命令查看系统中共享内存的情况,对两次的结果进行比较,并分析原因。最后用ipcrm命令删除自己建立的共享存储区。(有关ipcs和ipcrm介绍见后面一页)
addr=shmat(shmid,0,0);/*挂接,并得到共享区首地址*/
printf ("addr 0x%x\n",addr);
pint=(char *)addr;
for (i='a';i<='e';i++) *pint++=i;
pause();/*等待接收进程读*/
}
cleanup()
{
shmctl(shmid,IPC_RMID,0);
(2)每个同学登陆两个窗口,先在一个窗口中运行例3程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),然后在另一个窗口中运行例3程序2,观察程序的运行结果并分析。运行结束后可以用ctrl+c结束程序1的运行。
(3)编写程序:使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序。要求在父进程中生成一个30字节长的私有共享内存段。接下来,设置一个指向共享内存段的字符指针,将一串大写字母写入到该指针指向的存贮区。调用fork()生成子进程,让子进程显示共享内存段中的内容。接着,将大写字母改成小写,子进程修改共享内存中的内容。之后,子进程将脱接共享内存段并退出。父进程在睡眠5秒后,在此显示共享内存段中的内容(此时已经是小写字母)。
操作系统实验三(进程通信)

暨南大学本科实验报告专用纸课程名称《操作系统原理实验》成绩评定实验项目名称进程通信指导教师戴红实验项目编号0806002903 实验项目类型综合型实验地点学生姓名蔡高成学号2007052431学院国际商学院系企业管理专业信息管理与信息系统实验时间年月日下午温度℃湿度一、实验目的学习如何利用管道机制或消息缓冲队列进行进程间的通信,并加深对上述通信机制的理解。
提高学生分析问题和解决问题的能力,并学习撰写规范的科学研究报告。
二、实验环境及设备(一)实验室名称:计算机实验室(二)主要仪器设备:PC机、Linux操作系统环境三、实验内容编写一段程序,使用管道来实现父子进程之间的进程通信。
子进程项父进程发送自己的进程表示符,以及某字符串。
父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。
四、实验调试分析1、实验函数说明(1)pipe头文件:#include<unistd.h>定义函数:int pipe(int pipedes[2]);函数说明:pipe()会建立管道,并将文件描述词由参数pipedes 数组返回。
pipedes[0]为管道里的读取端,所以pipe用read调用的pipedes[1]则为管道的写入端。
写进程A pipedes[1]返回值: 若成功则返回零,否则返回-1,错误原因存于errno 中。
错误代码:EMFILE 进程已用完文件描述词最大量ENFILE 系统已无文件描述词可用。
EFAULT 参数pipedes 数组地址不合法。
(2)sprintf函数功能:把格式化的数据写入某个字符串头文件:#include <stdio.h>函数原型:int sprintf( char *buffer, const char *format [, argument] … );返回值:字符串长度(strlen)(3)flock头文件: #include<sys/file.h>定义函数: int flock(int fd,int operation);函数说明: flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。
实验三进程间通信

实验三进程间通信班级: xxx 学号: xxx 姓名: xxx 分数:1、实验目的:Linux系统的进程通信机构(IPC)允许在任意进程间大批量的交换数据。
本实验的目的是了解和熟悉Linux支持的通信机制、共享存储区机制及信号量机制。
2、实验预备内容:阅读Linux系统的等源码文件,熟悉Linux的三种通信机制。
3、实验内容:(1)消息的创建,发送和接收(2)使用系统调用msgget(),msgsnd(),msgrev()及msgctl()编制一长度为1k的消息发送和接收程序。
<程序设计>(1)为了便于操作和观察结果,用一个程序作为“引子”,先后fork()两个子进程,SERVER和CLIENT,进行通信。
(2)SERVER端建立一个Key为75的消息队列,等待其他进程发来的消息。
当遇到类型为1的消息,则作为结束信号,取消该队列,并退出SERVER。
SERVER每接收到一个消息后显示一句“(server)received”。
(3)CLIENT端使用Key为75的消息队列,先后发送类型从10到1的消息,然后退出。
最后一个消息,即是SERVER端需要的结束信号。
CLIENT每发送一条信息后显示一句“(client)sent”。
(4)父进程在SERVER和CLIENT均退出后结束。
4、源代码及运行截图:#include <>#include <sys/>#include <sys/>#include <sys/>#define MSGKEY 75struct msgform{long mtype;char mtext[1030];}msg;int msgqid,i;void CLIENT(){ int i;msgqid=msgget(MSGKEY,0777);for (i=10;i>=1;i--){=i;printf("(client)sent \n");msgsnd(msgqid,&msg,1024,0); /*发送消息msg入msgid消息队列*/}}void SERVER(){msgqid=msgget(MSGKEY,0777|IPC_CREAT); /*由关键字获得消息队列*/do{msgrcv(msgqid,&msg,1030,0,0); /*从msgid消息队列接收消息msg*/printf("(server)received \n");}while!=1); /*消息类型为1时,释放队列*/msgctl(msgqid,IPC_RMID,0);}void main(){while((i=fork())==-1);if(!i) SERVER();while((i=fork())==-1);if(!i) CLIENT();wait(0);wait(0);}5、实验感想本次实验的实验目的是了解和熟悉Linux支持的通信机制、共享存储机制及信号量机制。
操作系统实验三进程的管道通信精编版

操作系统实验三进程的管道通信精编版MQS system office room 【MQS16H-TTMS2A-MQSS8Q8-MQSH16898】实验三进程的管道通信一、实验目的:(1)加深对进程概念的理解,明确进程和程序的区别;(2)学习进程创建的过程,进一步认识并发执行的实质;(3)分析进程争用资源的现象,学习解决进程互斥的方法;(4)学习解决进程同步的方法;(5)掌握Linux系统进程间通过管道通信的具体实现方法。
二、实验内容及要求:(1)使用系统调用pipe()建立一条管道线,两个子进程分别向管道写一句话(写的内容自己定,但要有该进程的一些信息);(2)父进程从管道中读出来自两个子进程的消息,显示在屏幕上;(3)要求:父进程首先接收子进程p1发来的消息,然后再接收子进程p2发来的消息;(4)两个子进程要并发执行;(5)实现管道的互斥使用。
当一个子进程正在对管道进行写操作时,另一个欲写入管道的子进程必须等待。
使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定;(6)实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。
三、实现:相关的系统调用fork()用于创一个子进程。
格式:intfork();返回值:在子进程中返回0;在父进程中返回所创建的子进程的ID 值;当返回-1时,创建失败。
wait()常用来控制父进程与子进程的同步。
在父进程中调用wait(),则父进程被阻塞,进入等待队列,等待子进程结束。
当子进程结束时,父进程从wait()返回继续执行原来的程序。
返回值:大于0时,为子进程的ID值;等于-1时,调用失败。
exit()是进程结束时最常调用的。
格式:voidexit(intstatus);其中,status为进程结束状态。
pipe()用于创建一个管道格式:pipe(intfd);其中fd是一个由两个数组元素fd[0]和fd[1]组成的整型数组,fd[0]是管道的读端口,用于从管道读出数据,fd[1]是管道的写端口,用于向管道写入数据。
实验三_进程间通信 (1)

实验三线程控制和进程间通信一、实验目的通过Linux管道通信机制、消息队列通信机制的使用,加深对不同类型的进程通信方式的理解。
二、实验内容:1.熟悉Linux的管道通信机制2.熟悉Linux的消息队列通信机制三、思考1.有名管道和无名管道之间有什么不同?2.管道的读写与文件的读写有什么异同?3.Linux消息队列通信机制中与教材中的消息缓冲队列通信机制存在哪些异同?四、实验指导<一>Linux管道通信机制管道是所有UNIX都提供的一种进程间通信机制,它是进程之间的一个单向数据流,一个进程可向管道写入数据,另一个进程则可以从管道中读取数据,从而达到进程通信的目的。
1.无名管道无名管道通过pipe()系统调用创建,它具有如下特点:(1)它只能用于具有亲缘关系的进程(如父子进程或者兄弟进程)之间的通信。
(2)管道是半双工的,具有固定的读端和写端。
虽然pipe()系统调用返回了两个文件描述符,但每个进程在使用一个文件描述符之前仍需先将另一个文件描述符关闭。
如果需要双向的数据流,则必须通过两次pipe()建立起两个管道。
(3)管道可以看成是一种特殊的文件,对管道的读写与文件的读写一样使用普通的read、write等函数,但它不是普通的文件,也不属于任何文件系统,而只存在于内存中。
2.pipe系统调用(1)函数原型#include <unistd.h>int pipe(int filedes[2]);(2)参数filedes参数是一个输出参数,它返回两个文件描述符,其中filedes[0]指向管道的读端,filedes[1]指向管道的写端。
(3)功能pipe在内存缓冲区中创建一个管道,并将读写该管道的一对文件描述符保存在filedes所指的数组中,其中filedes[0]用于读管道,filedes[1]用于写管道。
(4)返回值成功返回0;失败返回-1,并在error中存入错误码。
(5)错误代码EMFILE:进程使用的文件描述符过多ENFILE :系统文件表已满EFAULT :非法参数filedes3.无名管道的阻塞型读写管道缓冲区有4096B的长度限制,因此,采用阻塞型读写方式时,当管道已经写满时,写进程必须等待,直到读进程取走信息为止。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
操作系统实验报告实验三、进程通信(一)——管道及共享内存一、实验目的熟悉和掌握LINUX系统的管道通信和共享内存通信。
二、实验内容(一)、管道通信1、实验原理:管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统。
数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。
利用系统调用pipe()可创建一个简单的管道。
int fd[2];pipe(fd);调用成功,fd[0]存放供读进程使用的文件描述符(管道出口),fd[1]存放供写程使用的文件描述符(管道入口)。
一个进程在由pipe()创建管道后,一般再fork()一个子进程,然后通过管道实现父子进程间的通信,子进程将从父进程那里继承所有打开的文件描述符。
则父子两个进程都能访问组成管道的两个文件描述符,这样子进程可以向父进程发送消息(或者相反)。
发送进程利用文件系统的系统调用write(fd[1],buf,size),把buf中size个字符送入fd[1],接收进程利用read(fd[0],buf,size),把从fd[0]读出的size个字符置入buf中。
这样管道按FIFO(先进先出)方式传送信息。
2、实验内容:#include<stdio.h>main(){ int x,fd[2];char buf[30],s[30];pipe(fd);while ((x=fork())==-1);if (x==0){close(fd[0]);printf("Child Process!\n");strcpy(buf,"This is an example\n");write(fd[1],buf,30);exit(0);}else{close(fd[1]);printf("Parent Process!\n");read(fd[0],s,30);printf("%s\n",s);printf("x value in Parent Process:%d!\n",x);}}(1)阅读上述父子进程利用管道进行通信的例子,写出程序的运行结果并分析。
程序运行x=fork()后,创建里一个子进程,在子进程里x的返回值为0,在父进程里x的返回值为7684,则子进程会执行if语句里的代码段,先关闭了管道的读入端,再在屏幕上输出“Child Process!”,然后将“This is an example\n”存入buf数组中,通过调用write()函数将buf数组的内容从管道的写入端写入,而父进程会执行else语句里的代码段,先关闭了管道的写入端,再在屏幕上输出“Parent Process!”,然后通过调用read ()函数将buf数组的内容从管道的读入端读入冰存储在s数组里,接着通过printf()函数将s数组里的内容输出到屏幕上,最后在屏幕上输出父进程中x的值。
(2)编写程序:父进程利用管道将一字符串交给子进程处理。
子进程读字符串,将里面的字符反向后再交给父进程,父进程最后读取并打印反向的字符串。
#include<stdio.h>main(){ int i,x,fd[2];char buf[20],s[20],cpy[20],m[20];strcpy(buf,"This is an example\n");pipe(fd);write(fd[1],buf,20);while ((x=fork())==-1);if (x==0){printf("Child Process!\n");read(fd[0],s,20);for(i=0;i<20;i++){cpy[i]=s[19-i];}write(fd[1],cpy,20);exit(0);}else{close(fd[1]);printf("Parent Process!\n");read(fd[0],m,20);printf("%s\n",m);}}(二)、共享内存通信1、实验原理:UNIXSystem V IPC软件包分三个组成部分:(1) 共享存储器(shared memory)方式可使得不同进程通过共享彼此的虚拟空间而达到互相对共享区操作和数据通信的目的。
(2) 消息(message)用于进程之间传递分类的格式化数据。
(3) 信号量(semaphore)机制用于通信进程之间往前推进时的同步控制。
信号量总是和共享存储器方式一起使用。
操纵共享内存共有4个系统调用:(1)shmget() :建立一个新的共享区或返回一个已存在的共享存储区描述字;int shmget(key_t key,int size,int shmflag);成功,返回共享内存段的标识符;失败,返回-1,设置errno。
①第一个参数key(键值),预定义的数据类型key_t,其类型是长整型。
用来创建IPC标识符,shmget()返回的标识符与key值一一对应,不同的key值返回不同的标识符。
②第二个参数size,决定了共享内存段的大小(若访问已存在的内存段,该参数可设为0)。
有最大字节数的限制,0x2000000=32M;③第三个参数shmflag,用于设置访问权限及标识创建条件。
#define IPC_PRIV ATE ((key_t)0)#define IPC_CREAT 00001000(八进制)#define IPC_EXCL 00002000(八进制)key值为IPC_PRIV ATE时,调用shmget()将生成一个新的共享内存段。
Shmflag为0666|IPC_CREAT时,如果key值是新的,返回新创建的内存段标识符。
若key值是旧的,返回已存在内核中的具有相同关键字值的内存段标识符。
(2)shmat():连接内存段,映射到自己的地址空间中;int shmat(int shmid,void *shmaddr,int shmflag);成功:返回该共享内存段连接到调用进程地址空间上的地址(指针)错误:返回-1。
第一个参数shmid,是一个有效的共享内存标识符;第二个参数shmaddr,非0,该值作为挂接的地址,设为0,则由系统来选择挂接地址;第三个参数shmflag,可指定挂接后的访问权限,(默认情况0)。
(3)shmdt() :当某个进程不需要一个共享内存段时,调用该系统调用,断开与该内存段的连接。
int shmdt(void *shmaddr);成功:返回0;错误:返回-1。
参数shmaddr指向一个已挂接的内存段。
(4)shmctl():用户对一个存在的共享内存段进行一系列的操作;int shmctl(int shmid,int cmd,struct shmid_ds *buf);成功:返回0;错误:返回-1,设置errno。
第一个参数shmid,前面shmget()调用返回的有效的共享内存标识符;第二个参数cmd,指明shmctl将要执行的操作;第三个参数buf,指向一个shmid_ds类的结构。
Cmd可执行的操作:(这些也是在/usr/include/linux/ipc.h中定义的)IPC_STAT:返回由shmid值指定的存贮段shmid_ds结构的当前值。
IPC_SET:修改shmid_ds结构中反问权限子结构的若干成员IPC_RMID:删除shmid指向的内存段(并非真正删除,只有当前连接到该内存段的最后一个进程正确地断开了与它的连接,实际的删除操作才会发生)。
附:1、ipcs命令的作用:用于查看系统中共享存储区,消息队列和信号量的情况。
2、ipcrm命令的作用:用于删除系统中存在的共享存储区,消息队列等。
如:ipcrm -M key 表示根据关键字删除共享存储区ipcrm -m id表示根据标识符删除共享存储区ipcrm -Q key表示根据关键字删除消息队列ipcrm -q id表示根据标识符删除消息队列2、实验内容:(1)阅读例2的程序,运行一次该程序,然后用ipcs命令查看系统中共享存储区的情况,再次执行该程序,再用ipcs命令查看系统中共享内存的情况,对两次的结果进行比较,并分析原因。
最后用ipcrm命令删除自己建立的共享存储区。
#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>main(){key_t key=69;int shmid_1,shmid_2;if ((shmid_1=shmget(key,1000,0644|IPC_CREAT))= = -1){perror("shmget shmid_1");exit(1);}printf("First shared memory identifier is %d\n",shmid_1);if ((shmid_2=shmget(IPC_PRIV ATE,20,0644))= = -1){perror("shmget shmid_2");exit(2);}printf("Second shared memory identifier is %d\n",shmid_2);exit(0);}key值为IPC_PRIV ATE时,调用shmget()将生成一个新的共享内存段。
(2)每个同学登陆两个窗口,先在一个窗口中运行例3程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),然后在另一个窗口中运行例3程序2,观察程序的运行结果并分析。
运行结束后可以用ctrl+c结束程序1的运行。
例3:(程序1)#include <sys/types.h>#include <sys/ipc.h>#define SHMKEY 69#define K 1024int shmid;main (){int i,*pint;char *addr;extern char * shmat ();extern cleanup ();for(i=0;i<20;i++) signal(i,cleanup);shmid=shmget(SHMKEY,16*K,0777|IPC_CREAT); /*建立16K共享区SHMKEY */addr=shmat(shmid,0,0);/*挂接,并得到共享区首地址*/printf ("addr 0x%x\n",addr);pint=(int *)addr;for (i=0;i<256;i++) *pint++=i;pause();/*等待接收进程读*/}cleanup(){shmctl(shmid,IPC_RMID,0);exit ();}例3:(程序2)#include <sys/types.h>#include <sys/ipc.h>#define SHMKEY 69#define K 1024int shmid;main (){int i,*pint;char *addr;extern char * shmat ();shmid=shmget(SHMKEY,8*K,0777);/*取共享区SHMKEY的id */ addr=shmat(shmid,0,0);/*连接共享区*/pint=(int *)addr;for (i=0;i<256;i++)printf("%d ",*pint++);/*打印共享区中的内容*/}在后台运行的例3的程序1:首先系统通过调用shmctl()对shmid指向的内存段进行删除操作,接着系统调用shmget()创建一个16K的共享内存段,成功返回共享内存段的标识符给shmid,系统再次调用shmat()连接内存段,返回共享内存段连接到调用进程地址空间上的地址addr,最后向该共享内存段中写入数据;终端运行的例3的程序2:首先系统调用shmget()创建一个8K的共享内存段,由key与程序1相同,所以返回给shmid的值与程序1所创建的共享内存段的标识符相同,再通过调用shmat()挂接内存段,由shmid与程序1相同,所以挂接到程序1所创建的共享内存段,最后读取该共享内存段的数据并输出到屏幕上。