操作系统实验进程通信共享存储区和信号量.docx
《操作系统实验进程通信共享存储区和信号量.docx》由会员分享,可在线阅读,更多相关《操作系统实验进程通信共享存储区和信号量.docx(18页珍藏版)》请在冰豆网上搜索。
操作系统实验进程通信共享存储区和信号量
实验报告
实验题目
姓名:
学号:
课程名称:
操作系统实验
所在学院:
信息科学与工程学院
专业班级:
计算机
任课教师:
实验项目名称
进程通信——共享存储区和信号量
一、实验目的与要求:
1、了解和熟悉共享存储机制
2、了解和熟悉信号量机制
3、熟悉信号量机制中使用的数据结构和信号量机制的操作以及控制。
4、了解共享主存段机制,学会对共享主存段的系统调用。
二、实验设备及软件:
1、PC机一台
2、Linux操作系统
三、实验方法(原理、流程图)
一、共享存储区
1、共享存储区机制的概念
共享存储区(ShareMemory)是UNIX系统中通信速度最高的一种通信机制。
该机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。
另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。
当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虚地址空间上。
此后,进程对该区的访问操作,与对其虚地址空间的其它部分的操作完全相同。
进程之间便可通过对共享存储区中数据的读、写来进行直接通信。
图示列出二个进程通过共享一个共享存储区来进行通信的例子。
其中,进程A将建立的共享存储区附接到自己的AA’区域,进程B将它附接到自己的BB’区域。
应当指出,共享存储区机制只为进程提供了用于实现通信的共享存储区和对共享存储区进行操作的手段,然而并未提供对该区进行互斥访问及进程同步的措施。
因而当用户需要使用该机制时,必须自己设置同步和互斥措施才能保证实现正确的通信。
二、涉及的系统调用
1、shmget()
创建、获得一个共享存储区。
系统调用格式:
shmid=shmget(key,size,flag)
参数定义:
intshmget(key,size,flag);
key_tkey;
intsize,flag;
其中,key是共享存储区的名字;size是其大小(以字节计);flag是用户设置的标志,如IPC_CREAT。
IPC_CREAT表示若系统中尚无指名的共享存储区,则由核心建立一个共享存储区;若系统中已有共享存储区,便忽略IPC_CREAT。
附:
操作允许权八进制数
用户可读00400
用户可写00200
小组可读00040
小组可写00020
其它可读00004
其它可写00002
控制命令值
IPC_CREAT0001000
IPC_EXCL0002000
例:
shmid=shmget(key,size,IPC_CREAT|0640)
创建一个关键字为key,长度为size的共享存储区,该共享存储区允许用户自己进行读写访问,只允许同组用户进行读访问。
2、shmat()
共享存储区的附接。
从逻辑上将一个共享存储区附接到进程的虚拟地址空间上。
系统调用格式:
virtaddr=shmat(shmid,addr,flag)
参数定义:
char*shmat(shmid,addr,flag);
intshmid,flag;
char*addr;
其中,shmid是共享存储区的标识符;addr是用户给定的,将共享存储区附接到进程的虚地址空间,当为0时,表示由操作系统分配一个地址;flag其值为SHM_RDONLY时,表示只能读;其值为0时,表示可读、可写;其值为SHM_RND(取整)时,表示操作系统在必要时舍去这个地址。
该系统调用的返回值是共享存储区所附接到的进程虚地址viraddr。
3、shmdt()
把一个共享存储区从指定进程的虚地址空间断开。
系统调用格式:
shmdt(addr)
参数定义:
intshmdt(addr);
charaddr;
其中,addr是要断开连接的虚地址,亦即以前由连接的系统调用shmat()所返回的虚地址。
调用成功时,返回0值,调用不成功,返回-1。
4、shmctl()
共享存储区的控制,对其状态信息进行读取和修改。
系统调用格式:
shmctl(shmid,cmd,buf)
参数定义:
intshmctl(shmid,cmd,buf);
intshmid,cmd;
structshmid_ds*buf;
其中,buf是用户缓冲区地址,cmd是操作命令。
命令可分为多种类型:
(1)用于查询有关共享存储区的情况。
如其长度、当前连接的进程数、共享区的创
建者标识符等;
(2)用于设置或改变共享存储区的属性。
如共享存储区的许可权、当前连接的进程
计数等;
(3)对共享存储区的加锁和解锁命令;
(4)删除共享存储区标识符等。
上述的查询是将shmid所指示的数据结构中的有关成员,放入所指示的缓冲区中;而设置是用由buf所指示的缓冲区内容来设置由shmid所指示的数据结构中的相应成员。
三、信号量机制的概念
信号量(semaphore)与其它进程通信方式不同,它主要提供对进程间共享资源访问的控制机制。
进程可以根据它判定是否能够访问某共享资源,同时,进程也可以修改它的值。
除了用于访问控制外,还可用于进程同步。
LINUX/UNIX支持的是系统V信号量机制,是计数信号量集。
相关数据结构在/usr/include/linux/sem.h中有定义,图示如下:
四、相关的系统调用
1、semget()
创建、获得一个信号量集描述符。
系统调用格式:
semid=semget(key,nsems,flag)
参数定义:
intsemget(key,nsems,flag);
key_tkey;
intnsems,flag;
其中,key是信号量集的名字;nsems是指该信号量集所包含信号量的个数;flag是用户设置的标志和访问方式,如:
IPC_CREAT|0400该信号量集是否已被创建,无则创建,是则打开;
IPC_EXCL|0400该信号量集的创建是互斥的,若已创建则失败;
semid是该系统调用返回的描述符,失败则返回-1。
2、semop()
对信号量集中一个或几个信号量进行操作。
系统调用格式:
semop(semid,sops,nsops)
参数定义:
intsemop(semid,sops,nsops)
intsemid
structsembuf*sops
unsignednsops
其中,semid是上述semget返回的描述符;sops是结构数组指针;nsops表示结构数组中成员个数。
structsembuf定义如下:
structsembuf{shortsem_num;
shortsem_op;
shortsem_flg;}
其中,sem_num表示所操作信号量在信号量集中位置,0对应第一个信号量;sem_op
表示对该信号量的改变值,sem_op>0表示进程要释放sem_op个共享资源,sem_op<0表
示进程要申请sem_op个资源;sem_flg可取值IPC_NOWAIT和SEM_UNDO,IPC_NOWAIT
表示申请资源不能满足时,进程并不等待,而是立即返回,告知申请失败,SEM_UNDO在进程结束时,相应的操作将被取消。
系统调用的返回值:
成功为0,否则为-1。
3、semctl()
对信号量集的控制操作
系统调用格式:
semctl(semid,semnum,cmd,arg)
参数定义:
intsemctl(semid,semnum,cmd,arg)
intsemid,semnum,cmd;
unionsemun
{
semid_ds*buf;
int*array;
intval;
}arg
其中,semid是上述semget返回的描述符;semnum指定对哪个信号量执行控制操作,
只对一些cmd操作有意义;arg用于设置或返回信息,其类型随cmd操作而定;cmd指定执行的操作,可允许的值和意义如下:
IPC_STAT获取信号量集信息,结果在arg.buf中
IPC_SET设置信号量集信息,设置信息由arg.buf提供
IPC_RMID删除该信号量集
SETALL设置或更新所有信号量的值,设置值由arg.array提供
GETALL获取所有信号量的值,结果保存在arg.array中
SETVAL设置semnum所指定信号量的值为arg.val
GETVAL返回semnum所指定信号量的值
GETNCNT返回等待semnum所指定信号量的值增加的进程数,即等待该共享资
源的进程数GETPID返回最后一个对semnum所指定信号量执行semop操作的进程ID
GETZCNT返回等待semnum所指定信号量的值变为0的进程数系统调用的返回值:
失败为-1,成功与cmd相关。
四、实验过程、步骤及内容
1、编制一长度为1k的共享存储区发送和接收的程序。
2、编制程序,使用信号量通信机制实现生产者—消费者问题。
参考代码1:
#include
#include
#include
#defineSHMKEY75
intshmid,i;int*addr;
voidclient()
{inti;
shmid=shmget(SHMKEY,1024,0777);/*打开共享存储区*/
addr=shmat(shmid,0,0);/*获得共享存储区首地址*/
for(i=9;i>=0;i--)
{while(*addr!
=-1);
printf("(client)sent\n");
*addr=i;
}
exit(0);
}
voidserver()
{
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT);/*创建共享存储区*/
addr=shmat(shmid,0,0);/*获取首地址*/
do
{
*addr=-1;
while(*addr==-1);
printf("(server)received\n");
}while(*addr);
shmctl(shmid,IPC_RMID,0);/*撤消共享存储区,归还资源*/
exit(0);
}
main()
{
while((i=fork())==-1);
if(!
i)server();
system(“ipcs-m”);
while((i=fork())==-1);
if(!
i)client();
wait(0);
wait(0);
}
参考代码2:
/*sem1.c*/
#include//共享存储区所用的头文件
#include
#include
#include
#defineSHMKEY70
#defineSEMKEY80
#defineK1024
typedefintarr[16][256];
intshmid;//全局变量
intsemid;
main()
{inti,in=0;
char*addr;//外部函数声明
arr*arrp;
structsembufops1={0,-1,SEM_UNDO},
ops2={1,1,SEM_UNDO};
externcleanup();
for(i=0;i<31;i++)
signal(i,cleanup);
shmid=shmget(SHMKEY,16*K,0777|IPC_CREAT);//建立256字节共享区SHMKEY
addr=shmat(shmid,0,0);//共享区首地址
arrp=(arr*)addr;//共享区的第一个字节为零时,等待,因为还没有写完
semid=semget(SEMKEY,2,0777|IPC_CREAT);//取共享存储区SHMKEY的id
semctl(semid,0,SETVAL,16);
semctl(semid,1,SETVAL,0);//撤消共享存储区,归还资源
for(i=0;i<256;i++)
{
semop(semid,&ops1,1);
(*arrp)[in][0]=i;
in=(in+1)%16;
semop(semid,&ops2,1);
}
sleep
(1);
}
cleanup()
{shmctl(shmid,IPC_RMID,0);
semctl(semid,0,IPC_RMID,0);
exit();
}
/*sem2.c*/
#include//共享存储区所用的头文件
#include
#include
#include
#defineSHMKEY70
#defineSEMKEY80
#defineK1024
typedefintarr[16][256];
intshmid;
intsemid;
main()
{inti,in=0;
char*addr;//外部函数声明
arr*arrp;
structsembufops1={1,-1,SEM_UNDO},
ops2={0,1,SEM_UNDO};
shmid=shmget(SHMKEY,16*K,0777);//建立256字节共享区SHMKEY
addr=shmat(shmid,0,0);//共享区首地址
arrp=(arr*)addr;//共享区的第一个字节为零时,等待,因为还没有写完
semid=semget(SEMKEY,2,0777);//取共享存储区SHMKEY的id
for(i=0;i<256;i++)
{
semop(semid,&ops1,1);
printf("sem2:
%d=%d\n",i,(*arrp)[in][0]);//打印共享区中的内容
in=(in+1)%16;
semop(semid,&ops2,1);
}
}
错误分析
在第二个例子中,首先进程向共享段写信息。
该进程创建了长度为16K的共享主存段,并将共享段附加到了地址空间为Addr的地址上。
然后从共享段的起始单元开始写入0~255个自然数。
等待接收进程读。
然后进程从共享段读信息的例子,该进程首先将进程写信息共享段的共享段连接到自己的地址空间,之后,判断共享段是否有信息,若无,则等待,否则,读信息并显示。
write进程创建了长度16k的共享主存段,并将共享段附加到了地址空间为addr的地址上,也显示了addr的值,然后从共享段的起始单元开始写入0-255个自然数,然后将首地址赋值为256,故读进程read运行后,第一个数显示256,后面是1-255。
这个程序最好在root下运行,在一般用户下运行不出结果。
五、实验数据(现象)处理分析
共享存储区通信文件:
共享存储区可执行文件shyan7:
生成可执行文件操作:
执行:
信号量通信文本文件:
信号量通信可执行文件sem1:
信号量通信生成可执行文件操作:
信号量通信文本文件:
信号量通信可执行文件sem2:
可执行文件2的生成操作:
可执行文件sem1和sem2合并运行结果如下图所示:
………………………
………………..
在第一个例子的程序中创建了5个并发子进程,互斥地对文件进行写操作,将自己的进程号写到文件中去,信号量的初值为1,当地一个进程执行update file函数时首先将信号量值-1.(相当于P操作)致使其它进程等待无法操作文件,直到其结束后,将其值变为1后(相当于V操作):
其它进程并发竞争对文件的写操作,并将目己的pid写入文件中。
六、实验结论
通过实验了解和熟悉了LINUX支持的信号量机制、管道机制、消息通信机制及共享存储区机制的基本原理和基本概念。
共享存储区机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。
还可以一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。
当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虑地址空间上。
共享主存段在系统调用时,首先得申请一个共享主存段之后才能对共享存储进御操作用。
对信号和中断有了进一步的理解,能够分辨出两者的区别和相似点。
观察实验现象知道了信号的发送方式和处理方式。
掌握了信号的发送,是指由发送进程把信号送到指定进程的信号域的某一位上。
如果目标进程正在一个可被中断的优先级上睡眠,核心便将它唤醒,发送进程就此结束。
一个程可能在其信号域中有多个位被置位,代表有多种类型的信号到达,但对于一类信号,进程却只能记住其中的某一个。
通过本次实验最终目的还是全面了解进程的各种机制以及处理方法。
七、教师批阅意见:
成绩评定:
教师签字:
年月日
八、备注: