《操作系统进程通信(信号,共享存储区,消息队列)》由会员分享,可在线阅读,更多相关《操作系统进程通信(信号,共享存储区,消息队列)(7页珍藏版)》请在金锄头文库上搜索。
1、操作系统实验三进程通信 1 / 7 实验三实验三 进程通信进程通信 (1)姓名:李欣 学号:2007202314 (2)实验题目:进程通信 (3)实验目的: 1.掌握进程间通讯的编程方法; 2.加深对进程并发执行的理解。 (4)实验方法 设计一个多进程并发运行的程序,它由不同的进程完成下列工作: 1.接收键盘输入进程 负责接收用户的键盘输入,并以适当的方式将由键盘获得的数据交给其它进程处理。 2.显示进程 负责全部数据显示任务,包括键盘输入数据的显示和提示信息的显示。 3.分发数据进程 将键盘输入的数据分为 3 类,即字母、数字和其它,并分别将字母写入文件 letter.txt 中,数字写入文
2、件 number.txt 中,除字母和数字外其它数据丢弃。 除上述要求外,程序必须能: 以适当的方式提示用户输入数据 提示用户有数据被丢弃 全部的显示任务必须由显示进程完成。 整个程序能够连续处理多组输入数据, 直到用户输入“quit”字符串, 整个程序程序结果。 (5)程序结构 数据结构: 1. 共享存储区: 主要实现语句: shmid=shmget(key,size,flag); shmat(shmid,addr,flag); shmdt(addr); shmctl(shmid,cmd,buf)。 2. 消息队列: 主要实现语句: struct my_msg long int my_msg
3、_type; 操作系统实验三进程通信 2 / 7 char textMAXSIZE; msg; int msgsnd ( int msqid, const void *prt, size_t nbytes, int flags); ssize_t msgrcv ( int msqid, void *ptr, size_t nbytes, long type , int flag); 程序结构: (6)实验结果 操作系统实验三进程通信 3 / 7 有代表性的执行结果: stud14localhost E3$ ./a.out Enter some text: operating system 12
4、34 Enter some text: lixin2007202314 Enter some text: quit Distributed over! There are chars discarded! letter.txt 内容为:operatingsystemlixin numbet.txt 内容为:12342007202314 结果分析及解释 1首先输出提示信息 Enter some text: ,提示输入文本。 2首先输入 operating system 1234 ,包括字母数字和无效字符。 3再次输出提示信息 Enter some text: 。 4输入 lixin2007202
5、314 5再次输出提示信息 Enter some text: 后输入 quit 退出。 6输出提示信息 Distributed over! (7)问题分析 1.子进程 1,即显示进程未写在循环体内,执行一次后就结束,以至于在下次需要显示提示信息时出现错误。 修改后将子进程 1 写在循环内, 只有当接收到 SIGUSR2 信号时才执行退出函数,从而实现对显示进程的随时调用,当程序结束时可让其正 常终止。具体代码为: while(1) signal(SIGUSR2,Over);/接受 SIGUSR2 信号时退出 signal(SIGUSR1,DONO); pause(); /从消息队列中读出信息输
6、出 msg.my_msg_type=1; msgid=msgget(14,0666); len=msgrcv(msgid, msg.textlen=0; printf(“%s“,msg.text); 2.在定义共享存储区是,将共享存储区定义过大,以至于不能申请成功,将大小改为 512 后可申请成功。 3. 对于函数 msgrcv 参数共有五个, 其中第三个参数 size_t nbytes 大小为结构体msg 中数组的大小,而不是整个结构体的大小。 4.对于 msg 中的 msg.my_msg_type,应给其赋大于 0 的初值。 操作系统实验三进程通信 4 / 7 5.当父进程给子进程 1 发
7、送信号后,原本是用 pasue()函数是父进程挂起,当 子进程 1 将信息输出后再将父进程用 kill 函数唤醒, 但在实际执行中, 父进程唤醒后再次向其他进程发送 kill 信号时总不能成功。因此将父进程中的 pause()函数改为 sleep() ,即可执行。具体代码为: strcpy(msg.text,“Enter some text:n“); msgsnd(msgid,/发送提示信息 kill(pid1,SIGUSR1);/向子进程 1 发送信号,以显示提示信息 sleep(1); 6.父进程使用 fgets()函数读入一行输入,fgets()函数读入结束时的回车符并自动添加字符串结束
8、符。 7.对于输入 “quit” 退出的解决,一开始使用函数 strncmp(buf,”quit”,4);但后来考虑到输入诸如”quitxy”等字符床也会退出,因此将 strncmp 改为 strcmp 函数,具体代码为: if(strcmp(buf,“quitn“)=0) break; 8.对于共享内存的互斥问题,一开始使用了信号量,但后来考虑到只有两个进程使用此共享内存,因此改用信号通信,当输入进程将全部信息复制到共享存储区 后即可执行分发进程即可。 9.对于想共享存储区内复制信息的过程,一开始使用 strcpy,于是后写入的信息 就将之前的信息覆盖掉了,于是改用函数 strcat,将后输
9、入的信息链接到之前的信息后,就不会造成数据丢失。具体代码为: shmid=shmget(1234,MAXSIZE,0666|IPC_CREAT); viraddr=(char*)shmat(shmid,0,0); strcat(viraddr,buf);/将输入内容写入共享存储区 10.当程序执行完毕后应取消消息队列和共享存储区。 (8)程序清单 可执行的程序清单: #include #include #include /#include #include #include #include #include #include #include #include #define MAXSIZE
10、 512 struct my_msg/ 定义消息结构体 long int my_msg_type; char textMAXSIZE; 操作系统实验三进程通信 5 / 7 msg; void DONO()/空函数 void Over()/进程退出函数 exit(0); int main() int pid1,pid2; int msgid,shmid; char *viraddr; char bufMAXSIZE; int i,len; int flag; FILE *fp_l,*fp_n; while(pid1=fork()=-1); if(pid1=0)/子进程 1,显示进程 while(
11、1) signal(SIGUSR2,Over);/接受 SIGUSR2 信号时退出 signal(SIGUSR1,DONO); pause(); /从消息队列中读出信息输出 msg.my_msg_type=1; msgid=msgget(14,0666); len=msgrcv(msgid, msg.textlen=0; printf(“%s“,msg.text); else while(pid2=fork()=-1); if(pid2=0)/子进程 2,字符分配进程 signal(SIGUSR2,DONO); 操作系统实验三进程通信 6 / 7 pause(); flag=0; /获得共享内
12、存区域并读出信息 shmid=shmget(1234,MAXSIZE,0666|IPC_CREAT); viraddr=(char*)shmat(shmid,0,0); strcpy(buf,viraddr); i=0; fp_l=fopen(“letter.txt“,“w“); fp_n=fopen(“number.txt“,“w“); while(bufi!=0)/将信息按规则分配 if(bufi=A else flag=1; i+; /关闭文件 fclose(fp_l); fclose(fp_n); exit(flag);/返回 falg 值 else/父进程,读入进程 /创建消息队列
13、msgid=msgget(14,0666|IPC_CREAT); msg.my_msg_type=1; while(1) strcpy(msg.text,“Enter some text:n“); msgsnd(msgid,/发送提示信息 kill(pid1,SIGUSR1);/向子进程 1 发送信号,以显示提示信息 sleep(1); fgets(buf,MAXSIZE,stdin); if(strcmp(buf,“quitn“)=0) break; shmid=shmget(1234,MAXSIZE,0666|IPC_CREAT); viraddr=(char*)shmat(shmid,0
14、,0); strcat(viraddr,buf);/将输入内容写入共享存储区 kill(pid2,SIGUSR2); 操作系统实验三进程通信 7 / 7 wait( strcpy(msg.text,“Distributed over!n“); msgsnd(msgid, kill(pid1,SIGUSR1); sleep(1); if(flag=0) strcpy(msg.text,“No chars discarded!n“); msgsnd(msgid, kill(pid1,SIGUSR1); sleep(1); else strcpy(msg.text,“There are chars discarded!n“); msgsnd(msgid, kill(pid1,SIGUSR1); sleep(1); kill(pid1,SIGUSR2);/终止子进程 1 shmdt(viraddr); shmctl(shmid,IPC_RMID,0); semctl(mute,IPC_RMID,0); msgctl(msgid,IPC_RMID,0); return 0;