共享内存和信号量进程间通信word资料12页.docx
- 文档编号:11829443
- 上传时间:2023-04-03
- 格式:DOCX
- 页数:11
- 大小:19.59KB
共享内存和信号量进程间通信word资料12页.docx
《共享内存和信号量进程间通信word资料12页.docx》由会员分享,可在线阅读,更多相关《共享内存和信号量进程间通信word资料12页.docx(11页珍藏版)》请在冰豆网上搜索。
共享内存和信号量进程间通信word资料12页
实验7共享内存和信号量(进程间通信)
邢卫2008-11-26修订
实验目的
学习并掌握Linux系统中的进程间通信机制,包括共享内存和信号量。
实验内容
1.学习共享内存相关的系统调用
shmget(),shmat(),shmdt,shmctl()
2.学习信号量(semaphore)相关的系统调用
semget(),semop(),semctl()
3.学习信号(signal)相关的系统调用
signal(),atexit()等
4.完成《边干边学》第6.4.1节的实验程序的编辑、编译、运行操作
5.分析、学习实验程序的工作过程和原理
6.选做:
学习《边干边学》第6章,结合使用联机手册(可以从man2ipc命令开始),编程练习各种进程间通信机制
实验步骤
1.以stu帐号登录
2.编辑reader_writer1.c程序
注意:
在193页delete()函数中,注意改成
if(mysemctl(Semid,0,IPC_RMID,(unionsemun)0)==-1){
限于实验的时间,该文件已预先存放在/home/stu/.kernel/lab6目录下,可以直接使用。
但每位同学务必通读并理解该程序。
登录后,使用cd.kernel/lab6命令进入该文件所在目录,继续以下实验步骤。
3.编译gccreader_writer1.c-oreader_writer1
4.运行./reader_writer1
注意记录下共享内存的id号
5.使用Alt+F2切换到第2个登录窗口,再次以stu帐号登录
可以使用who命令查看验证此时有两个stu用户已登录
可以使用ps–l命令查看这两个stu用户的进程
6.在第2个stu用户窗口中,输入./reader_writer1共享内存的id号
注意:
此时,第2个stu用户窗口中的进程担当writer角色,第1个stu用户窗口中的进程担当reader角色。
7.在第2个窗口中,多次输入信息;使用Alt+F1和Alt+F2在两个窗口间切换,观察你对writer的输入,writer已经通过共享内存传递给了reader。
8.此时,你还可以使用Alt+F3切换到第3个登录窗口,并以stu帐号登录
可以使用who命令验证有3个stu用户登录;
可以经常性使用ps–l命令来查看另外两个窗口中的进程的状态
9.切换到writer窗口(第2个窗口),通过对writer的问题回答“2”,退出writer。
切换到reader窗口(第1个窗口),通过Ctrl+C终止reader进程。
思考题
1.同样的源程序,reader和writer进程是怎样各自找到自己的定位的?
2.reader和writer是怎样通过信号量(semphore)实现同步的?
writer是如何得知这一对信号量的id的?
3.数据是如何从writer传递到reader的?
4.writer是如何得知共享内存的id的?
5.在reader中,是如何捕获Ctrl-C信号(signal)的?
捕获后是如何处理的?
6.一般来说,在Linux中使用共享内存(sharedmemory)的流程应该怎样?
使用哪些系统调用?
7.一般来说,在Linux中使用信号量(semaphore)的流程应该怎样?
使用哪些系统调用?
8.这里的共享内存,和使用带CLONE_VM标志的clone()系统调用创建的两个task之间共享的内存,有什么异同?
参考资料
●《边干边学》(第1版)第6章,“共享内存”
⏹具体源程序和实验操作详见6.4.1节
附录1
共享内存的使用
共享内存共有4个系统调用:
shmget,shmat,shmdt,shmctl
intshmget(key_tkey,intsize,intshmflg);
典型的创建共享内存的用法
●shmid=shmget(key,size,IPC_CREAT|IPC_EXCL|mode);
●shmid=shmget(IPC_PRIVATE,size,mode);
void*shmat(intshmid,constvoid*shmaddr,intshmflg);
典型用法:
●shmaddr=shmat(shmid,NULL,0);
intshmdt(constvoid*shmaddr);
intshmctl(intshmid,intcmd,structshmid_ds*buf);
典型用法:
●取状态shmctl(shmid,IPC_STAT,&buf);
●删除shmctl(shmid,IPC_RMID,NULL);
实例
structshmid_dsbuf;
shmid=shmget(key,size,flag);
if(shmid==-1){
//errorhandling...
shmctl(shmid,IPC_STAT,&buf);
//分析利用buf中的信息
shmaddr=(char*)shmat(id,NULL,0);
if(shmaddr==-1){
//errorhandling...
通过shmaddr使用共享内存的部分,如strcpy,sprintf,memcmp,赋值操作,等等
shmdt(shmaddr);
shmctl(shmid,IPC_RMID,NULL);
附录2实验原理说明
本实验将建立一个利用共享内存来传递信息的程序,一个writer,一个reader,writer从用户处获得输入,然后将其写入共享内存,reader从共享内存获取信息,然后再在屏幕上打印出来。
利用共享内存在进程之间传递信息时,需要一种同步机制,必须有一种途径让reader知道什么时候writer已经把信息放入了共享内存。
最简单的方法,是在某处设置一个字节,当writer的数据写入完毕后,即把该字节设置为1。
但是这也意味着reader必须不停地测试这个字节,直到该字节改变为止,这是非常浪费的。
同样,对于writer来说,也必须有一种途径知道什么时候reader已经取走了共享内存的数据,从而可以向共享内存写入新的数据。
因此,我们考虑用信号量(semaphore)来解决这个程序对于共享内存进行操作的同步问题,关于信号量的编程,请参考Linuxman手册。
目前这个程序只支持两个进程,一个reader,一个writer。
在稍后的时候,我们将改进这个程序使得其能够支持任意数目的进程。
在这个程序中,我们使用两个信号量,一个用于读(SN_READ),一个用于写(SN_WRITE)。
SN_READ初始化为1,SN_WRITE初始化为0。
即SN_READ这个信号量在最初的时候就是被锁住的,而SN_WRITE这个信号量则不是。
writer在往共享内存里写信息时,首先要锁定SN_WRITE信号量。
在写完之后,释放SN_READ信号量,使得reader可以读取该信息;锁定SN_WRITE这个信号量,是为了防止writer多次打印共享内存中的信息。
reader读取共享内存的信息时,相应地要先锁定SN_READ这个信号量,读取信息后,释放SN_WRITE这个信号量,使得writer又可以往共享内存里面写入信息。
程序源代码参见reader_writer1.c。
编译:
gccreader_writer1.c–oreader_writer1
在此之后,即可启动reader。
实验中必须先启动reader,因为使用的信号量、共享内存都是在reader中申请的。
在命令行输入:
./reader_writer1
运行结果为:
readerbegintorun,andtheidofsharememoryis229376
waitforthewriter’soutputinformation...
然后再启动writer,带的参数为reader申请的共享内存的标识符。
在命令行输入:
./reader_writer1229376
运行结果为:
writerbegintorun,theidofsharememoryis229376,semaphoreidis196608
menu
1.sendamessage
2.quit
inputyourchoice(1-2):
1
waitforreadertoreadininformation...finish
pleaseinputinformation:
在提示后面输入:
hello,reader
随即,reader那边将打印这条信息。
然后循环往复。
不再累赘。
关于退出:
writer可以通过菜单退出,reader可以在writer退出后,按Ctrl+C退出,退出reader时,它将自动删除最初申请信号量。
附录3reader_write1.c源程序
/****reader_writer1.ccommunicatethroughsharedmemory****/
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*Theunionforsemctlmayormaynotbedefinedforus.Thiscode,definedinlinux'ssemctl()manpage,istheproperwaytoattainitifnecessary*/
#ifdefined(__GNU_LIBRARY__)&&!
defined(_SEM_SEMUN_UNDEFINED)
/*unionsemunisdefinedbyincluding
#else
/*accordingtoX/OPENwehavetodefineitourselves*/
unionsemun{
intval;/*valueforSETVAL*/
structsemid_ds*buf;/*bufferforIPC_STAT,IPC_SET*/
unsignedshortint*array;/*arrayforGETALL,SETALL*/
structseminfo*__buf;/*bufferforIPC_INFO*/
#endif
#defineSHMDATASIZE1000
#defineBUFFERSIZE(SHMDATASIZE-sizeof(int))
#defineSN_READ0
#defineSN_WRITE1
intSemid=0;
voidreader(void);
voidwriter(intshmid);
voiddelete(void);
voidsigdelete(intsignum);
voidlocksem(intsemid,intsemnum);
voidunlocksem(intsemid,intsemnum);
voidwaitzero(intsemid,intsemnum);
voidwrite(intshmid,intsemid,char*buffer);
intmysemget(key_tkey,intnsems,intsemflg);
intmysemctl(intsemid,intsemnum,intcmd,unionsemunarg);
intmysemop(intsemid,structsembuf*sops,unsignednsops);
intmyshmget(key_tkey,intsize,intshmflg);
void*myshmat(intshmid,constvoid*shmaddr,intshmflg);
intmyshmctl(intshmid,intcmd,structshmid_ds*buf);
intmain(intargc,char*argv[]){
/*nocommandlineparameter,areader*/
if(argc<2){
reader();
}else{
writer(atoi(argv[1]));
return0;
voidreader(void){
unionsemunsunion;
intsemid,shmid;
void*shmdata;
char*buffer;
/*first,createasemaphore*/
semid=mysemget(IPC_PRIVATE,2,SHM_R|SHM_W);
Semid=semid;
/*atexit,deletethesemaphore*/
atexit(&delete);
signal(SIGINT,&sigdelete);
sunion.val=1;
mysemctl(semid,SN_READ,SETVAL,sunion);
sunion.val=0;
mysemctl(semid,SN_WRITE,SETVAL,sunion);
/*createasharedmemory*/
shmid=myshmget(IPC_PRIVATE,SHMDATASIZE,IPC_CREAT|SHM_R|SHM_W);
/*mapthesharedmemoryintotheprocess'virtualmemory*/
shmdata=shmat(shmid,0,0);
/*markthesharedmemoryas"destroyed",andleaveittobe
destroyedautomatically*/
shmctl(shmid,IPC_RMID,NULL);
*(int*)shmdata=semid;
buffer=shmdata+sizeof(int);
printf("\nreaderbegintorun,andtheidofsharememoryis%d**\n",shmid);
reader'smainloop
while
(1){
printf("\nwaitforthewriter'soutputinformation...");
fflush(stdout);
locksem(semid,SN_WRITE);
printf("finish\n");
printf("receivedinformation:
%s\n",buffer);
unlocksem(semid,SN_READ);
voidwriter(intshmid){
intsemid;
void*shmdata;
char*buffer;
/*mapthesharedmemoryintoprocess'virtualmemory*/
shmdata=myshmat(shmid,0,0);
semid=*(int*)shmdata;
buffer=shmdata+sizeof(int);
printf("\nwriterbegintorun,theidofsharememoryis%d,thesemaphoreis%d\n",shmid,semid);
writer'smainloop
while
(1){
charinput[3];
printf("\nmenu\n1.sendamessage\n");
printf("2.quit\n");
printf("inputyourchoice(1-2):
");
fgets(input,sizeof(input),stdin);
switch(input[0]){
case'1':
write(shmid,semid,buffer);break;
case'2':
exit(0);break;
voiddelete(void){
printf("\nquit;deletethesemaphore%d\n",Semid);
/*deletethesemaphore*/
if(mysemctl(Semid,0,IPC_RMID,(unionsemun)0)==-1){
printf("Errorreleasingsemaphore.\n");
voidsigdelete(intsignum){
/*Callingexitwillconvenientlytriggerthenormaldeleteitem.*/
exit(0);
voidlocksem(intsemid,intsemnum){
structsembufsb;
sb.sem_num=semnum;
sb.sem_op=-1;
sb.sem_flg=SEM_UNDO;
mysemop(semid,&sb,1);
voidunlocksem(intsemid,intsemnum){
structsembufsb;
sb.sem_num=semnum;
sb.sem_op=1;
sb.sem_flg=SEM_UNDO;
mysemop(semid,&sb,1);
voidwaitzero(intsemid,intsemnum){
structsembufsb;
sb.sem_num=semnum;
sb.sem_op=0;
sb.sem_flg=0;/*Nomodificationsononeedtoundo*/
mysemop(semid,&sb,1);
voidwrite(intshmid,intsemid,char*buffer){
printf("\nwaitforreadertoreadininformation...");
fflush(stdout);
locksem(semid,SN_READ);
printf("finish\n");
printf("pleaseinputinformation:
");
fgets(buffer,BUFFERSIZE,stdin);
unlocksem(semid,SN_WRITE);
intmysemget(key_tkey,intnsems,intsemflg){
intretval;
retval=semget(key,nsems,semflg);
if(retval==-1){
printf("semgetkey%d,nsems%dfailed:
%s",
key,nsems,strerror(errno));
exit(255);
returnretval;
intmysemctl(intsemid,intsemnum,intcmd,unionsemunarg){
intretval;
retval=semctl(semid,semnum,cmd,arg);
if(retval==-1){
printf("semctlsemid%d,semnum%d,cmd%dfailed:
%s",
semid,semnum,cmd,strerror(errno));
exit(255);
returnretval;
intmysemop(intsemid,structsembuf*sops,unsignednsops){
intretval;
retval=semop(semid,sops,nsops);
if(retval==-1){
printf("semopsemid%d(%doperations)failed:
%s",
semid,nsops,strerror(errno));
exit(255);
returnretval;
intmyshmget(key_tkey,intsize,intshmflg){
intretval;
retval=shmget(key,size,shmflg);
if(retval==-1){
printf("shmgetkey%d,size%dfailed:
%s",
key,size,strerror(errno));
exit(255);
returnretval;
void*myshmat(intshmid,constvoid*shmaddr,intshmflg){
void*retval;
retval=shmat(shmid,shmaddr,shmflg);
if(retval==(void*)-1){
printf("shmatshmid%dfailed:
%s",shmid,strerror(errno));
exit(255);
returnretval;
intmyshmctl(intshmid,intcmd,structshmid_ds*buf){
intretval;
retval=shmctl(shmid,cmd,buf);
if(retval==-1){
printf("shmctlshmid%d,cmd%dfailed:
%s",
shmid,cmd,strerror(errno));
exit(255);
returnretval;
希望以上资料对你有所帮助,附励志名言3条:
1、生气,就是拿别人的过错来惩罚自己。
原谅别人,就是善待自己。
2、未必钱多乐便多,财多累己招烦恼。
清贫乐道真自在,无牵无挂乐逍遥。
3、处事不必求功,无过便是功。
为人不必感德,无怨便是德。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 共享 内存 信号量 进程 通信 word 资料 12