操作系统实验二

操作系统实验二报告

Y,xj

一,进程树寻找

  • 实验要求:打开一个vi进程。通过ps命令以及选择合适的参数,只显示名字为vi的进程。寻找vi进程的父进程,直到init进程为止。记录过程中所有进程的ID和父进程ID。将得到的进程树和由pstree命令的得到的进程树进行比较

  • 实验步骤

    • (一) 使用PS命令查询父进程
    • 使用ps -ef命令 显示所有进程 寻找vi的父进程
      在这里插入图片描述
      1552866969513
      在这里插入图片描述
    • 根据以上三个图我们可以寻找到进程号为3461的vi进程,通过寻找其父进程可以找到进程树 3461—>3450—>3442—>2681—>1658—>1025—>1
    • (二)使用PSTREE命令查询进程树
    • 终端输入pstree可得到如下进程树
    • 在这里插入图片描述
      在这里插入图片描述
    • 可以看到 我们得到的进程树结果是一样的

二,fork函数调用

  • 实验要求:编写程序,首先使用fork系统调用,创建子进程。在父进程中继续执行空循环操作;在子进程中调用exec打开vi编辑器。然后在另外一个终端中,通过ps –Al命令、ps aux或者top等命令,查看vi进程及其父进程的运行状态,理解每个参数所表达的意义。选择合适的命令参数,对所有进程按照cpu占用率排序。
  • 实验步骤
    • (一)熟悉fork函数使用操作

    • 调用fork函数,系统会将代码复制,并新建一个进程继续往下执行,会产生两个返回值,若返回值为-1,则说明创建子进程失败,若返回值为0,则进入子进程,若返回值是一个大于0的数,则此部分为主进程,这个大于0的数为子进程的进程号

    • (二)程序编写

    • 实验要求子进程打开vi编辑器,主进程实现空循环。

    • 子进程通过execl函数调用vi命令打开编辑器

    • 主进程用空循环来起到保持程序运行状态的作用

      #include<stdio.h>
      #include<unistd.h>
      #include<stdlib.h>
      
      int main()
      {
      	int pid;
      	pid=fork();
      	switch(pid)
      	{
      		case -1:
      			printf("fork fail!\n");
      			exit(1);
      		case 0:					//子进程打开vi编辑器部分	
      			execl("/usr/bin/vi","vi","/home/yxj/Desktop/OStest2",NULL);
      			printf("exec fail!\n");
      			exit(1);
      		default:			//主进程执行for循环维持进程正常执行
      			for (int i=0;;i++){};
      			printf("vi completed!\n");
      			exit(1);
      	}
      }
      
    • (注):主进程若不写循环,则主进程会先于子进程执行完,则子进程会出现<defunct>僵尸进程的情况,如下图前两次

    • 在这里插入图片描述

    • 上图第三次ps -a命令显示的结果为正确执行结果,子进程打开了vi编辑器,主进程依旧在执行

    • (三)查看每个进程的状态及cpu占用

    • 在这里插入图片描述

    • 终端输入top可以看到,改命令将主机中的所有进程全部动态显示了出来,并且按照cpu使用率进行了排序,主进程cpu占用率为99.7%,状态为R,是执行状态,下面的sl状态是休眠状态

三,fork函数创建进程树

  • 实验要求:使用fork系统调用,创建如下进程树,并使每个进程输出自己的ID和父进程的ID。观察进程的执行顺序和运行状态的变化。

    在这里插入图片描述

  • 实验步骤

    • 代码逻辑分析:P1为此代码执行的主进程,产生2个子进程P2,P3,在P2进程中,再fork创建两个子进程P4,P5

参考代码

#include "stdio.h"
#include "sys/types.h"
#include "unistd.h"
#include "stdlib.h"

int main()
{
	pid_t p1, p2, p3, p4, p5;
	int cnt=0;
	printf("p1's pid is %d,and its parent_pid is %d\n", getpid(),getppid());
    //输出P1主进程的进程号和父进程号
	while ((p2 = fork()) == -1);
	if (p2==0)			//P2进程
	{
		printf("p2's pid is %d,and its parent_pid is %d\n", getpid(), getppid());
		p4 = fork();			
		if (p4 == 0)			//进入P4子进程
		{
		printf("p4's pid is %d,and its parent_pid is %d\n", getpid(), getppid());
		}
		else{
		p5 = fork();
		if (p5 == 0)			//进入P5子进程
		{
			printf("p5's pid is %d,and its parent_pid is %d\n", getpid(), getppid());
		}}
	}
	else
	{
		p3=fork();
		if (p3 == 0)			//进入P3子进程
		{
			printf("p3's pid is %d,and its parent_pid is %d\n", getpid(), getppid());
		}
	}
}
  • 运行结果

    • 在实验中发现,如果if后面不加else,则会多创建出来一些进程,原因是每个进程所复制的代码都会将后面没有else约束的创建进程代码执行一遍,所得结果如下图所示:

    • 在这里插入图片描述

    • 该结果中产生了2个P5进程,可以观察到他们的进程号不同,实则是2个进程

    • 在每个if后面加上else后,输出则为期望输出,如下图所示:

    • 在这里插入图片描述

    • 在这里插入图片描述

    • 从两次所得到的结果可以看出,进程创建的顺序并不一样

      [注]:我们看到有几个程序的父进程是很奇怪的(如2859,2172),进程号和其他差很多的一个进程,结果查询我们发现可能是由于父进程提前结束,而导致此进程变成了一个孤儿进程(interesting的名字),都交由一个系统的upstart父进程统一管理(即上述进程号的进程)。

四,终止进程

  • 实验要求:修改上述进程树中的进程,使得所有进程都循环输出自己的ID和父进程的ID。然后终止p2进程(分别采用kill -9 、自己正常退出exit()、段错误退出),观察p1、p3、p4、p5进程的运行状态和其他相关参数有何改变。

  • 实验步骤

    (一)修改代码:由于要实现不停的循环输出进程号,所以为了避免程序卡在输出不动,将每个子进程的输出语句都放在进程创建的后面。

参考代码

#include "stdio.h"
#include "sys/types.h"
#include "unistd.h"
#include "stdlib.h"

int main()
{
	pid_t p1, p2, p3, p4, p5;
	int cnt = 0;
	while ((p2 = fork()) == -1);   //防止进程创建失败
	if (p2 == 0)			//P2进程
	{
		int a[5];
		p4 = fork();
		if (p4 == 0)
		{
			while (1)
			{
				printf("p4's pid is %d,and its parent_pid is %d\n", getpid(), getppid());
			}
		}
		else {
			p5 = fork();
			if (p5 == 0)
			{
				while (1)
				{
					printf("p5's pid is %d,and its parent_pid is %d\n", getpid(), getppid());
				}
			}
		}
		while (1)
		{
			printf("p2's pid is %d,and its parent_pid is %d\n", getpid(), getppid());
		}
	}
	else
	{
		p3 = fork();
		if (p3 == 0)
		{
			while (1)
			{
				printf("p3's pid is %d,and its parent_pid is %d\n", getpid(), getppid());
			}
		}
	}
	while (1)
	{
		printf("p1's pid is %d,and its parent_pid is %d\n", getpid(), getppid());
	}
}

(二)执行程序:执行程序后每个进程都循环输出自己的进程号和父进程号,如下图所示:

在这里插入图片描述

每个进程状态如下

在这里插入图片描述
(三)kill杀死进程2:找到进程2的pid号4937,在另一个终端中输入kill -9 -4937,终止掉进程2

在这里插入图片描述
​ 可以看到,进程2已经成为defunct状态,其子进程的父进程都变成了2859,都成为了孤儿哈哈哈哈哈,

(四)exit退出进程:在代码中p2的部分添加一行exit(0);

在这里插入图片描述

​ 可以看到,进程2的状态变为了Zombie(Z),僵尸程序状态,其两个子进程又变成了孤儿

​ **(五)Segmentation Fault:**在代码中p2子进程下加入一行段错误程序

int *p=NULL;
*p=3;

​ 进程二就会自动退出,结果如下:

1552874468028

五,代码github地址:

https://github.com/Yxj-yxj/OS/tree/master/Lab2

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值