写给看这篇博客的杭电学弟:
按理说操作系统实验应该自己做,这样能锻炼自己。鉴于我的报告还是比较有参考价值,能让以后的同学参考一下,就做成md的形式。
实验三报告
一、实验内容:
(1)实验名:Linux进程管理
(2)实验要求:
1)实现一个模拟的shell
2)实现一个管道通信程序
3)利用Linux消息队列通信机制实现两个线程间的通信
4)利用Linux共享内存通信机制实现两个进程间的通信
二、实验思路
(1)实验一
pid = fork()会返回多个值,只需在fork()后使用多个判断语句即可。
pid<0表示错误,我打印error之后退出
pid=0表示子进程运行,使用execl替换进程,替换为我们想要的进程,如cmd.o。
pid>0表示父进程运行,使用wait(NULL)函数等待所有子进程的退出。
效果见实验结果(1)
代码见附录demo1
(2)实验二
使用7个信号量:
Mutex = sem_open(“Mutex”, O_CREAT, 0666, 1);
send1 = sem_open(“send1”, O_CREAT, 0666, 1);
send2 = sem_open(“send2”, O_CREAT, 0666, 1);
send3 = sem_open(“send3”, O_CREAT, 0666, 1);
receive1 = sem_open(“receive1”, O_CREAT, 0666, 0);
receive2 = sem_open(“receive2”, O_CREAT, 0666, 0);
receive3 = sem_open(“receive3”, O_CREAT, 0666, 0);
1)
建立无名管道:
int fd[2];
int ret = pipe(fd);//无名管道
2)先fork三个子进程,编写各自的操作
每个子进程等待各自的send信号量,再等待Mutex信号量,进行,完成后释放各自的receiver:
P(send)
P(Mutex)
。。。发送内容到管道。。。
V(receiver)
V(Mutex)
父进程等待三个receiver信号量,接收管道内容后,释放三个send信号量:
P(receiver1)
P(receiver2)
P(receiver3)
P(Mutex)
。。。发送内容到管道。。。
V(receiver1)
V(receiver2)
V(receiver3)
V(Mutex)
效果见实验结果(2)
代码见附录demo2
(3)实验三
四个信号量:
sem_send = sem_open(“send”, O_CREAT, 0666, 1);
sem_receive = sem_open(“receive”, O_CREAT, 0666, 0);
sem_over1 = sem_open(“over1”, O_CREAT, 0666, 0);
sem_over2 = sem_open(“over2”, O_CREAT, 0666, 0);
发送:(以sender1为例)
While(1)
{
P(send)
发送消息给接收消息队列
if(发送的是”exit”)
Break;
P(receive)
}
P(over1)
发送退出消息
V(send)
退出
接收:
Int flag1 = 0;
Int flag2 = 0;
While(1)
{
P(receive)
发送消息给接收消息队列
if(接收到的是1发来的”exit”)
Flag1 = 1
V(over1)
if(接收到的是2发来的”exit”)
Falg2 = 1
V(over2)
P(send)
If(flag1 && flag2)
Break;
}
退出
代码见附录demo3
(4)实验四
1)
共享内存中放的是字符串
支持不断地发送,不断地接收(加接收延时即可)
在发送消息中,第一位表示是哪个发送者发送的,以此区分发送者。
2)
sem_send = sem_open(“send”, O_CREAT, 0666, 2);
sem_receive = sem_open(“receive”, O_CREAT, 0666, 0);
sem_over1 = sem_open(“over1”, O_CREAT, 0666, 0);
sem_over2 = sem_open(“over2”, O_CREAT, 0666, 0);
发送:
While(1)
P(send)
发送信息
V(receive)
P(over1)
显示传回信息
V(send)
接收:
Int flag1 = 0;
Int flag2 = 0;
While(1)
P(receive)
If(是sender1发送的)
If(发送的是“exit”)
Flag1 = 1
V(over1)
If(是sender2发送的)
If(发送的是“exit”)
Falg2 = 1
V(over2)
三、实验结果与遇到的问题
(1)实验一
遇到的问题及解决:一开始父进程没有等待子进程结束导致出错
(2)实验二
经测试,可以做到不同顺序!.:
遇到的问题及解决:一开始连续三个fork(),其实创建了孙子进程,并不是三个并列的子进程,正确写法是:
pid1 = fork();
if(pid1 > 0)
{
pid2 = fork();
if(pid2 > 0)
{
pid3 = fork();
}
}
遇到的问题及解决:接收的数据乱码。原因是当初放数据时,没有考虑‘\0’的存在,应该合理设计,只在最后加‘\0’。
(3)实验三
支持多终端发送,单终端接收。
发送顺序不是固定。
遇到的问题及解决:无法申请到消息队列,试过各种方法,都是返回-1。重启就行了,估计是调试太多次,把能用的消息队列都搞没了。
(4)实验四
支持多终端发送,单终端接收。
发送顺序不是固定。
四、实验总结
这个实验我是最早验收成功的。一开始,投机求巧,只完成第四个小实验的多终端,而第三个小实验依旧使用单终端多线程(参考网上的),刚好贾老师出差就找赵伟华老师验收,是想让自己碰碰运气,结果运气不好只演示第三个,结果分数有点低。一开始的心态的确和大多数人一样,觉得水水过就好了,后来看到室友都实现了第三个实验的多终端,我也不甘示弱,还是把第三个小实验重写了一下。
六、附录
(1)Demo1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
char input[20];
pid_t pid;
// printf("输入要运行的程序名$\n");
// scanf("%s", input);
while(1)
{
printf("输入要运行的程序名$\n");
scanf("%s", input);
if(strcmp(input,"exit") == 0)
{
printf("父进程退出\n");
printf("\n进程结束,pid:%d\n", getpid());
exit(0);
}
else if(strcmp(input,"cmd3") == 0 || strcmp(input,"cmd2") == 0 || strcmp(input,"cmd1") == 0)
{
//创建子进程
pid = fork();
if(pid < 0)
{
printf("vfork() error\n");
exit(-1);
}
else if(pid == 0)
{
printf("i am the child process, my process id is %d\n",getpid());
char path[80] = "../t1/";
char *lastName = ".o";
strcat(path, input);
strcat(path, lastName);
execl(path,"",NULL);
}
else
{
printf("i am the parent process, my process id is %d\n",getpid());
pid_t temp = wait(NULL);
printf("\n进程结束,pid:%d\n", temp);
}
}
else
{
printf("Command not found\n");
// printf("输入要运行的程序名$\n");
// scanf("%s", input);
continue;
}
}
return 0;
}
(2)Demo2
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>//信号量头文件
#include <signal.h>
#define MAX_PIPE_CAPACIPY 100
int main()
{
int fd[2];
sem_t *Mutex;
sem_t *send1, *send2, *send3;
sem_t *receive1, *receive2, *receive3;
sem_unlink("Mutex");
sem_unlink("send1");
sem_unlink("send2");
sem_unlink("send3");
sem_unlink("receive1");
sem_unlink("receive2");
sem_unlink("receive3");
Mutex = sem_open("Mutex", O_CREAT, 0666, 1);
send1 = sem_open("send1", O_CREAT, 0666, 1);
send2 = sem_open("send2", O_CREAT, 0666, 1);
send3 = sem_open("send3", O_CREAT, 0666, 1);
receive1 = sem_open("receive1", O_CREAT, 0666, 0);
receive2 = sem_open("receive2", O_CREAT, 0666, 0);
receive3 = sem_open("receive3", O_CREAT, 0666, 0);
int ret = pipe(fd);//无名管道
if