实验三进程通信一管道及共享内存.docx
- 文档编号:29625249
- 上传时间:2023-07-25
- 格式:DOCX
- 页数:15
- 大小:266.45KB
实验三进程通信一管道及共享内存.docx
《实验三进程通信一管道及共享内存.docx》由会员分享,可在线阅读,更多相关《实验三进程通信一管道及共享内存.docx(15页珍藏版)》请在冰豆网上搜索。
实验三进程通信一管道及共享内存
操作系统实验报告
实验三、进程通信
(一)
——管道及共享内存
一、实验目的
1)加深对管道通信的了解
2)掌握利用管道进行通信的程序设计
3)了解共享内存通信的程序设计方法
4)了解和熟悉Linux支持的共享存储区机制
二、实验内容
任务一、
(1)阅读以上父子进程利用管道进行通信的例子(例1),写出程序的运行结果并分析。
(2)编写程序:
父进程利用管道将一字符串交给子进程处理。
子进程读字符串,将里面的字符反向后再交给父进程,父进程最后读取并打印反向的字符串。
任务二、
(1)阅读例2的程序,运行一次该程序,然后用ipcs命令查看系统中共享存储区的情况,再次执行该程序,再用ipcs命令查看系统中共享内存的情况,对两次的结果进行比较,并分析原因。
最后用ipcrm命令删除自己建立的共享存储区。
(有关ipcs和ipcrm介绍见后面一页)
(2)每个同学登陆两个窗口,先在一个窗口中运行例3程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),然后在另一个窗口中运行例3程序2,观察程序的运行结果并分析。
运行结束后可以用ctrl+c结束程序1的运行。
(3)编写程序:
使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序。
要求在父进程中生成一个30字节长的私有共享内存段。
接下来,设置一个指向共享内存段的字符指针,将一串大写字母写入到该指针指向的存贮区。
调用fork()生成子进程,让子进程显示共享内存段中的内容。
接着,将大写字母改成小写,子进程修改共享内存中的内容。
之后,子进程将脱接共享内存段并退出。
父进程在睡眠5秒后,在此显示共享内存段中的内容(此时已经是小写字母)。
三、代码及运行结果分析
(1)阅读以上父子进程利用管道进行通信的例子(例1),写出程序的运行结果并分析
实验代码:
#include
main()
{intx,fd[2];
charbuf[30],s[30];
pipe(fd);
while((x=fork())==-1);
if(x==0)
{
close(fd[0]);
printf("ChildProcess!
\n");
strcpy(buf,"Thisisanexample\n");
write(fd[1],buf,30);
exit(0);
}
else{
close(fd[1]);
printf("ParentProcess!
\n");
read(fd[0],s,30);
printf("%s\n",s);
}
}
运行结果:
分析:
调用pipe(fd);创建一个管道后,接着调用fork()函数产生两个进程,首先开始执行子进程,关闭管道出口,通过管道入口向管道中写入内容。
执行if语句后,进入else语句块内开始父进程,管道入口关闭,通过管道出口端从管道中读取之前写入内容,最后输出出来
(2)编写程序:
父进程利用管道将一字符串交给子进程处理。
子进程读字符串,将里面的字符反向后再交给父进程,父进程最后读取并打印反向的字符串。
实验代码:
#include
main()
{intx,count,left,right,temp,fd[2],fe[2];
charc,buf[30],s[30];
pipe(fd);
pipe(fe);
printf("pleaseinputalineofchar");
scanf("%s",buf);
while((x=fork())==-1);
if(x==0)
{
close(fd[0]);
close(fe[1]);
printf("ChildProcess!
\n");
write(fd[1],buf,30);
read(fe[0],buf,30);
printf("%s\n",buf);
exit(0);
}
else{
close(fd[1]);
close(fe[0]);
count=0;
do
{read(fd[0],&c,1);
s[count++]=c;
}while(c!
='\0');
printf("ParentProcess!
\n");
printf("%s\n",s);
count-=2;
for(left=0,right=count;left<=count/2;left++,right--){
temp=s[left];
s[left]=s[right];
s[right]=temp;
}
write(fe[1],s,30);
wait(0);
}
运行结果:
(3)阅读例2的程序,运行一次该程序,然后用ipcs命令查看系统中共享存储区的情况,再次执行该程序,再用ipcs命令查看系统中共享内存的情况,对两次的结果进行比较,并分析原因。
最后用ipcrm命令删除自己建立的共享存储区。
(有关ipcs和ipcrm介绍见后面一页)
实验代码:
#include
#include
#include
main()
{
key_tkey=208;/*在实际实验过程中,为了避免每个同学建立的共享存储区关键字一样而相互干扰,关键字请用学号末3位*/
intshmid_1,shmid_2;
if((shmid_1=shmget(key,1000,0644|IPC_CREAT))==-1){
perror("shmgetshmid_1");exit
(1);
}
printf("Firstsharedmemoryidentifieris%d\n",shmid_1);
if((shmid_2=shmget(IPC_PRIVATE,20,0644))==-1){
perror("shmgetshmid_2");exit
(2);
}
printf("Secondsharedmemoryidentifieris%d\n",shmid_2);
exit(0);
}
运行结果:
Ipcs查看:
再次运行:
再次用ipcs查看:
Ipcrm删除
分析:
成功,返回共享内存段的标识符,内核中用于唯一的标识一个对象。
对存在于内核存贮空间中的每个共享内存段,内核均为其维护着一个数据结构shmid_ds。
失败,返回-1,设置errno。
①第一个参数key(键值)用来创建IPC标识符,shmget()返回的标识符与key值一一对应,不同的key值返回不同的标识符。
②第二个参数size,决定了共享内存段的大小(若访问已存在的内存段,该参数可设为0)。
有最大字节数的限制
③第三个参数shmflag,用于设置访问权限及标识创建条件。
对两次的结果进行比较:
两次运行结束后的第二个共享标识符是不一样的。
在用ipcs查看时,共享内存段中的关键字,共享内存标识符,访问权限,字节等都是不一样的。
(4)每个同学登陆两个窗口,先在一个窗口中运行例3程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),然后在另一个窗口中运行例3程序2,观察程序的运行结果并分析。
运行结束后可以用ctrl+c结束程序1的运行。
实验代码:
#include
#include
#include
#defineSHMKEY208/*在实际实验过程中,为了避免每个同学建立的共享存储区关键字一样而相互干扰,关键字请用学号末3位*/
#defineK1024
intshmid;
main()
{
inti,*pint;
char*addr;
externchar*shmat();
externcleanup();
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("addr0x%x\n",addr);
pint=(int*)addr;
for(i=0;i<256;i++)*pint++=i;
pause();/*等待接收进程读*/
}
cleanup()
{
shmctl(shmid,IPC_RMID,0);
exit();
}
运行结果:
分析:
首先系统通过调用shmctl对shmid指向的内存段进行删除操作,接着系统调用shmget创建一个16*1024字节的共享内存段,成功返回共享内存段的标识符给shmid,系统再次调用shmat连接内存段,返回该共享内存段连接到调用进程地址空间上的地址addr。
实验代码:
#include
#include
#include
#defineSHMKEY208/*在实际实验过程中,为了避免每个同学建立的共享存储区关键字一样而相互干扰,关键字请用学号末3位*/
#defineK1024
intshmid;
main()
{
inti,*pint;
char*addr;
externchar*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\n",*pint++);/*打印共享区中的内容*/
}
运行结果:
分析:
例3_1程序后台运行时,该程序开始执行,系统调用shmget创建一个8*1024字节的共享内存段,再通过调用shmat挂接内存段,由系统选择挂接地址,最终输出转换后的挂接地址。
需要指出的是,共享存储区机制只为通信进程提供了访问共享存储区的操作条件,而对通信的同步控制则要依靠信号量机制等才能完成。
(5)编写程序:
使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序。
要求在父进程中生成一个30字节长的私有共享内存段。
接下来,设置一个指向共享内存段的字符指针,将一串大写字母写入到该指针指向的存贮区。
调用fork()生成子进程,让子进程显示共享内存段中的内容。
接着,将大写字母改成小写,子进程修改共享内存中的内容。
之后,子进程将脱接共享内存段并退出。
父进程在睡眠5秒后,在此显示共享内存段中的内容(此时已经是小写字母)。
实验代码:
#include
#include
#include
#defineSHMKEY208/*在实际实验过程中,为了避免每个同学建立的共享存储区关键字一样而相互干扰,关键字请用学号末3位*/
#defineK1024
intshmid;
main()
{
inti;
char*pint;
char*addr;
externchar*shmat();
externcleanup();
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("addr0x%x\n",addr);
pint=(char*)addr;
for(i='a';i<='e';i++)*pint++=i;
pause();/*等待接收进程读*/
}
cleanup()
{
shmctl(shmid,IPC_RMID,0);
exit();
}
#include
#include
#include
#defineSHMKEY208/*在实际实验过程中,为了避免每个同学建立的共享存储区关键字一样而相互干扰,关键字请用学号末3位*/
#defineK1024
intshmid;
main()
{
inti;
char*pint;
char*addr;
externchar*shmat();
shmid=shmget(SHMKEY,8*K,0777);/*取共享区SHMKEY的id*/
addr=shmat(shmid,0,0);/*连接共享区*/
pint=(char*)addr;
for(i=0;i<5;i++)
printf("%c\n",-32+*pint++);/*打印共享区中的内容*/
}
结果无法正确运行
四、实验心得
通过本次实验了解了管道进程间通信形式,,管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;单独构成一种独立的文件系统:
管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统。
数据的读出和写入:
一个进程向管道中写的内容被管道另一端的进程读出。
基本达到了本次实验的要求。
另外,对于共享内存也有一定的了解,学会通过创建多个管道实现父子进程间的通信,对于共享内存通信的工作机制也有了一定的了解,总之,本次实验自己收获了很多。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验三进程通信一 管道及共享内存 实验 进程 通信 管道 共享 内存