




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、甘肃政法学院本科生实验报告(四)姓名:杨万学院:计算机科学专业:计算机科学与技术 班级:2009级计本实验课程名称:操作系统实验实验日期:2012年6月8 日指导教师及职称:何珍祥实验成绩:开课时间:2011-2012学年 第二学期甘肃政法学院实验管理中心印制实验题目 进程的管道及消息通信小组合作否姓名杨万班级2009级计本学 号200981010142一、实验目的熟悉UNIX和linux操作系统进程通信的系统调用。理解和掌握UNIX和LINUX进程通信系统的调用的功能,给出了进程通讯实现机制中的使用的系统调用命令的格式和如何利用系统调用命令进行进程通信编程,通过学习,提高对进程之间
2、可通过系统的编程能力。二实验环境1. 操作系统Windows XP2.装有虚拟机Linux的系统三、实验内容与步骤 一.管道通信机制通过使用管道实现两个或多个进程之间的通信。所谓管道,就是能将一个进程的标准输出与另一个进程的标准输入联系在一起,进行通信的一种方法。同组进程之间可用无名管道任意通信,而不同组进程之间可通过有名管道进行通信。1. 无名管道的通信(1) 创建无名管道的格式#include<sys/types.h>#include<ctype.h>#include<unistd.h>int pipe(int filedes2);真确返回:0,错误返回
3、:-1。无名管道pipe()的使用例子:使用无名管道pipe(),进行父子进程之间的通信。源代码如下:#include<sys/types.h>#include<ctype.h>#include<unistd.h>int pipe(int filedes2);char parent="A message to pipe'communication.n"main() int pid,chan12; char buf100; pipe(chan1); pid=fork(); if(pid<0) printf("to c
4、reate child errorn"); exit(1); if(pid>0) close(chan10); printf("parent process sends a message to child.n"); write(chan11,parent,sizeof(parent); close(chan11); printf("parent process waits the child to terminaten"); wait(0); printf("parent process terminaten");
5、else close(chan11); read(chan10,buf,100); printf("The message read by child process from parent is :%s.n",buf); close(chan10); printf("child process terminatesn"); 2. 以命令行为参数的管道通信(1)命令格式#include<stdio.h>#include<sys/types.h>#include<ctype.h>FILE popen(const char
6、 cmdstring,const char type);真确返回:文件结构的指针;错误返回:空指针。Int pclose(FILE *fp);真确返回:cmdstring文件结构的指针;错误返回:-1。(2) 打开一个以命令行为参数的管理文件,完成进程之间的通信进程例子:以命令行为参数的管理文件的示例。 假设有一个的可执行程序chcase,从标准输出设备读字符,将小写字母转换成大写字母并进行输出。主程序使用popen创建管道,实现将某文件中的字母转换成大写字母。其中的文本文件名作为参数传进来。源程序如下:#include<sys/wait.h>#include<stdio.h
7、>#define MAXLINE 100int main(int argc,char *argv) char lineMAXLINE; FILE *fpin,*fpout; if(argc!=2) fprintf(stderr,"usage:a.out<pathname>n"); exit(1); if(fpin=fopen(argv1,"r")=NULL) fprintf(stderr,"can't open %s n",argv1); exit(1); if(fpout=popen("/mnt/
8、usb/mldm/chcase.exe","w")=NULL) fprintf(stderr,"popen errorn"); exit(1); while(fgets(line,MAXLINE,fpin)!=NULL) if(fputs(line,fpout)=EOF) fprintf(stderr,"fputs error to pipe. n"); exit(1); if(ferror(fpin) fprintf(stderr,"fgets error. n"); exit(1); if(pclos
9、e(fpout)=-1) fprintf(stderr,"pclose error. n"); exit(1); exit(0);3. 有名管道的通信(1) 创建一个有名管道的系统调用mknod()有名管道的使用方法与无名管道不同。有名管道可被任何知道其名字的进程打开和使用。为了使用有名管道,进程要先建立它,并与它的一端相连。创建有名管道的进程的进程叫服务器进程,存取管道的其他进程叫客户端。通信双方必须首先创建有名管道后,才能打开管道进行读写。当文件不再需要时,要显示删除。创建一个有名管道的命令同创建一个目录文件,特殊文件一样,使用如下命令:#include<sys/
10、types.h>#include<sys/stat.h>#include<unistd.h>#include<fcntl.h>Int mknod(const char *pathname,mode-t mode,dev-t dev);或#include<sys/types.h>#include<sys/stat.h>Int mkfifo(const char *pathname,mode-t mode);(2) 打开一个有名管道由于有名管道创建时并没有打开,因此必须显示的使用如下的系统调用将文件打开。Open(pathname,
11、oflg);(3) 有名管道使用的例子;代码如下:#include<sys/types.h>#include<sys/stat.h>#include<unistd.h>#include<fcntl.h>int mknod(const char *pathname,mode_t mode,dev_t dev);char string ="this is a example to show fifo communication"main(argc,argv)int argc;char *argv; int fd; char buf
12、256; int i; mknod("fifo",010777,0); if(argc=2) fd=open("fifo",O_WRONLY); else fd=open("fifo",O_RDONLY); for(i=0;i<26;i+) if(argc=2) printf("n Ihave wrote:%s",string); write(fd,string,45); string0+=1; else read(fd,buf,256); printf("n The context by I ha
13、ve read is :!%s",buf); buf0='0' close(fd);二消息缓冲机制 消息缓冲是unix系统进程之间进行大量数据交换的机制之一。消息缓冲是基于消息队列的,发送进程将消息挂入接收进程的消息队列,接收进程从消息队列中接收消息。消息是指具有类型和数量的一个数据。消息分为私有和公有的,如果消息是私有的,只能被创建消息队列的进程和其子进程访问;如果是公有的,可以被系统中知道消息队列名的所有进程访问。消息可以安类型访问,因此,不必按序访问。1. 消息缓冲使用的数据结构 为了实现消息缓冲,系统设置了相应的数据结构,下面是其结构和应用。(1) 消息缓冲区
14、消息缓冲区是存放消息的,其结构定义如下:Struct msgbuf long mtype; Char mtextN;(2) 消息头结构 对应每一个消息缓冲区都有一个消息头结构对其进行描述,其结构定义如下:Struct msg Struct msg *msgnext;Long msgtype;Short msgts;Short msgspot;(3) 消息头结构表消息头结构表是由若干个消息头结构构成的数据。系统初始化时,就已开辟好。消息头结构表的定义如下:Struct msg MSGTQL;2. 利用消息缓冲区机制的通信过程例子创建一个公共消息队列,实现客户进程和服务者进程之间进行通信。客户进程
15、向服务者进程发送给客户。服务着进行接收消息,完成客户的服务请求后,再将服务结果以消息方式发送给客户。其具体实现描述为: 服务者进程用关键字SVKEY和标志IPCCREAT调用msgget()建立一个消息队列。得到其队列标识符msqid之后,用msqid调用msgrcv()j接收类型为REQ的消息。 客户进程用关键字SVKEY和标准msgget()得到消息队列标识符msqid,之后用msqid调用msgsnd()将自己的pid发送到消息队列(SVKEY)中,表示其所请求的服务,然后调用msgrcv()等待服务结果消息的到来。 服务者进程接收到请求服务的消息后进行服务工作,完成服务后客户进程发送回
16、一条消息,消息的类型为客户的标识pid,消息正文是服务者进程自己的标识pid。 客户进程收到服务结果信息后,显示两者的通信过程,下面给出客户进程和服务者进程通信示例的源程序:(1) 客户进程的通信过程#include<sys/types.h>#include<sys/ipc.h>#include<sys/msg.h>#define SVKEY 75#define REQ 1struct msgformlong mtype;/消息类型char mtext256;/消息正文main()struct msgform msg;int msqid,pid,* pint
17、;msqid = msgget(SVKEY,0777);/创建消息队列pid = getpid();/获得当前进程标识pint = (int *)msg.mtext;/获得消息正文首地址* pint = pid;/将客户进程的pid复制到消息缓冲区中msg.mtype = REQ;msgsnd(msqid,&msg,sizeof(int),0);/发送消息msgrcv(msqid,&msg,256,pid,0);/这里pid作为消息类型printf("client receive server's service result is server's
18、pid: %d n",pid);(2) 服务进程server.c代码如下所示:#include<sys/types.h>#include<sys/ipc.h>#include<sys/msg.h>#define SVKEY 75#define REQ 1struct msgformlong mtype;char mtext256;main()int msqid;struct msgform msg;int i,pid,* pint;msqid = msgget(SVKEY,0777 | IPC_CREAT);/创建消息队列for(;)msgrcv(
19、msqid,&msg,256,REQ,0);/接受客户发送的消息printf("server is doing the service for a client.n");pint = (int *)msg.mtext;pid = * pint;/获得客户pid,以便进行服务printf("server receive client's service request is client's pid: '%d'.n",pid);msg.mtype = pid;pid = getpid();/*经服务进程的的pid发送
20、给客户msgsnd(msqid,&msg,sizeof(int),0);将代码改为客户端和服务端发送一段信息,(3) 客户进程的通信过程#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#define SVKEY 75#define REQ 1struct msgformlong mtype;char mtext100;int main() struct msgform * msg, *recv_msg; int msqid;/p
21、id,/char *pint;char string = "Hello!My name is yangwan"msqid = msgget(SVKEY,0777);/pid = getpid();/ pint=(int*)msg.mtext;/*pint=pid;msg = (struct msgform * )malloc(sizeof(struct msgform) + strlen(string); msg->mtype=REQ;strcpy(msg->mtext,string);msgsnd(msqid,msg,strlen(msg->mtext)
22、+1,0);free(msg);/recv_msg = (struct msgform * )malloc(sizeof(struct msgform) +strlen(string);/msgrcv(msqid,recv_msg,strlen(recv_msg->mtext)+1,0,0);/printf("client recieve message is :%s .n",recv_msg->mtext);/free(recv_msg);msgrcv(msqid,msg,strlen(msg->mtext)+1,0,0);printf("cl
23、ient recieve message is:%s.n",msg->mtext);return 0;(2) 服务者进程的通信过程#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdio.h>#define SVKEY 75#define REQ 1struct msgformlong mtype;char mtext100;int msqid;int main() struct msgform *msg;/*ser_send_msg
24、; /int i,pid,*pint; msqid = msgget(SVKEY,0777|IPC_CREAT); for(;) msgrcv(msqid,msg,100,REQ,0); printf("server is doing the service for a client.n"); / pint = (int*)msg.mtext; /pid=*pint; printf("server receive client's message is:%s.n",msg->mtext); /msg.mtype = p /*pint =ge
25、tpid();msg = (struct msgform *)malloc(sizeof(struct msgform) + strlen("sent message yangwan");msg->mtype=REQ;strcpy(msg->mtext,"sent message yangwan"); msgsnd(msqid,msg,strlen(msg->mtext)+1,0); return 0; 3 信号量机制在UNIX系统V中,一个或多个信号量构成一个信号量集合。使用信号量机制用来实现进程间的同步和互斥,允许并发进程一次对一组
26、信号量进行相同或不同的操作。每个P,V操作不限于减1或加1,而是可以加减任何整数。在进程终止时,系统可以根据需要自动消除所有被进程操作过的信号量的影响。例子用于互斥共享文件的信号量的使用。代码如下:#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <time.h>#include <sys/types.h>#include<sys/wait.h>#include<linux/sem.h>#define NUM_PROCS 5#def
27、ine SEM_ID 250 #define FILE_NAME "tmp/sem_MUTEX"#define DELAY 400000void update_file(int sem_set_id, char *file_name_path, int number) struct sembuf sem_op; FILE *file; sem_op.sem_num =0; sem_op.sem_op = -1; sem_op.sem_flg =0; semop(sem_set_id, &sem_op,1); file = fopen(file_name_path,&
28、quot;w"); if(file) fprintf(file,"%dn",number); fclose(file); sem_op.sem_num =0; sem_op.sem_op =1; sem_op.sem_flg = 0; semop(sem_set_id,&sem_op, 1); void do_child_loop(int sem_set_id, char *file_name) pid_t pid =getpid(); int i,j; for(i=0;i<3;i+) update_file(sem_set_id, file_nam
29、e,pid); for(j=0;j<200000;j+); int main(int argc, char *argv) int sem_set_id,child_pid; union semun sem_val; int i,rc; sem_set_id = semget(SEM_ID, 1,IPC_CREAT |0600); if(sem_set_id =-1) perror("main's semget error"); exit(1); sem_val.val =1; rc =semctl(sem_set_id,0,SETVAL,sem_val); i
30、f(rc =-1) perror("main:setctl"); exit(1); for(i =0;i<NUM_PROCS; i+) child_pid = fork(); switch(child_pid) case -1: perror("fork()"); exit(0); case 0: do_child_loop(sem_set_id,FILE_NAME); exit(0); default:break; for(i = 0;i<10;i+) int child_status; wait(&child_status); p
31、rintf("main is done");fflush(stdout);return 0;4 共享主存段机制共享主存段为进程提供了直接通过主存进行通信的有效手段,不像消息缓存机制那样需要系统提供缓存,也不像pipe机制那样需要事先建立一个特殊文件,而是有通信双方直接访问某些共享虚拟存储器空间。在系统V中,系统管理一组共享主存段控制块。通信进程在使用共享主存段以前,首先提出申请,系统为止分配存储空间并返回共享主存段标识号。一个共享段建立后,进程把它被附加到自己的虚拟存储空间中。一个进程可以附加多个共享主存段。一个主存段一旦被附加到进程的虚拟机空间后,对它的访问以其他虚拟机的
32、访问完全相同。但为了保证共享主存段数据完整性,通信的进程之间要互斥的进行访问。当通信进程不再需要该共享主存段时,可使用命令将其与进程分离,从而使其进程的虚空间删除。为了理解进程通过共享主存段的通信过程,下面举例,一个是进程向共享段写信息的例子:一个是进行从共享段读信息的例子。代码如下:进程向共享段些信息的例子;#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#include<stdio.h>#define SHMKEY 75#define K 1024int shmid;mai
33、n() int i,*pint; char *addr; extern char *shmat(); shmid=shmget(SHMKEY,16*K,0777|IPC_CREAT); addr=shmat(shmid,0,0); printf("addr ox%xn",addr); pint=(int *)addr; for(i=0;i<256;i+) *pint+=i; pint=(int *)addr; *pint=256; pause();进程从共享段读信息的例子#include<sys/types.h>#include<sys/ipc.h&
34、gt;#include<sys/shm.h>#define SHMKEY 75#define K 1024int shmid;main() int i,*pint; char *addr; extern char *shmat(); shmid=shmget(SHMKEY,8*K,0777); addr=shmat(shmid,0,0); pint=(int *)addr; while(*pint=0); for(i=0;i<256;i+)printf("%dn",*pint+);四、实验过程与分析 一.管道通信机制1. 无名管道的通信分析:父进程先使用p
35、ipe(chan1)系统调用打开一个无名管道,之后创建一个子进程。子进程复制父进程的打开文件表。为了正确通信,父进程关闭读通道close(chan10),子进程分别关闭写通道close(chan11)。父进程向管道写,子进程从管道读。完成一次通信后,父进程分别关闭自己的写/读通道,管道文件消失。次进程先运行父进程,父进程向无名管道写一条消息,此时父进程等待子进程从管道读取消息,直到子进程结束,最后父进程结束。2. 以命令行为参数的管道通信 分析:本程序先运行chcase.c程序,生成chcase.exe可执行文件,次程序的目的是将小写字母转换成大写字母,主程序先打开文本文件,通过popen创建
36、一个可写管道,将命令行的chcase的输入与管道的输出连接起来,然后向管道输入数据,那么,命令行就可以通过管道连接收文本文件的数据了,可实现将文本文件中的小写字母转换成大写字母。3. 有名管道的通信进程间使用有名管道实现通信时,必须有三次同步。第一次是打开同步。当一个进程以读方式打开有名管道时,若已有写者打开过,则唤醒写着后继续前进,否则,睡眠等待写者。当一个进程以写方式打开有名管道时,若以有读者打开过,则唤醒读者继续前进,否则等到读者。第二次是读写同步。其同步方式与pipe相同。允许写者超前读者1024个字符。当一次写超过1024时,超前的字符要写入时,超前的字符要写入时,则写者必须等待,读
37、者从有名管道时,若没有可读则等待。若有数据可读,读完后要检测有无写者等待。若有唤醒写者。而且要求读写两方面随时检查通信的另一方是否还存在,一旦有一方不存在,应立即终止通信过程。第三次是关闭同步。当一个写进程关闭有名管道时,若发现有进程睡眠等待从管道读,则唤醒它,被唤醒进程立即从读调用返回。当一个读进程有名管道时,若发现有进程睡眠等待向管道写,则唤醒它,并向他发一个指示错误条件的信号后返回,最后一个关闭有名管道的进程,释放该管道占用的全部盘块及相应主存i节点。有名管道打开后,就可以使用读写命令进行读写,读写完成后就立即关闭。有名管道文件关闭后,文件本身并没有消失。有名管道的读。写和关闭动作与普通文件完全相同。2 消息缓冲机制哟运行结果该进程创建了一个公共消息队列,实现客户进程和服务者进程之间进行通信。客户进程向服务者进程发送消息,请求服务,服务者进程接收消息,完成客户的服务请求后,再将服务结果一消息发送给客户。具体实现描述为:服务者进程用关键字SVKEY和标志IPC_CRAT调用msgget()建立一个消息队列,得到其队列标识符msqid之后,用msqid调用msgrcv()接收类型为REQ的消息。客户进程用关键字SVKEY调用msgget
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 后浇带施工工程图纸3篇
- 公司车辆过户授权委托3篇
- 工业园区供电工程协议3篇
- 学生安全协议书范例3篇
- 供电公司全权代表授权委托书3篇
- 大班科学树的教案8篇
- 庆典活动合同范本3篇
- 公司经营代表全权授权委托书3篇
- 医疗机构双向转诊合同3篇
- 学生与校方入学协议模板3篇
- 全国AEFI监测方案
- DB3301∕T 0451-2024 医学美容机构电子病历系统技术规范
- 《大国浮沉500年:经济和地理背后的世界史》记录
- 水工维护初级工技能鉴定理论考试题库(含答案)
- 运维项目进度计划
- 商场中央空调租赁协议模板
- 十八项核心制度
- 浙江省杭州市2023-2024学年六年级下学期期中模拟测试数学试卷(人教版)
- 国家开放大学《Python语言基础》实验4:条件分支结构基本应用参考答案
- OTA代运营协议文档
- 内分泌科常见急危重症抢救流程
评论
0/150
提交评论