操作系统实验二:进程控制
1、找父进程并构建进程树
打开一个vi进程。
新开起一终端,通过ps -C vi
或ps -e | grep vi
命令,显示名字为vi的进程。
ps -C vi
只显示名字为vi的进程信息
ps -e | grep vi
则显示名字里带有vi的进程
grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
可以看到名字为vi的进程的信息,进程号为2721
寻找vi进程的父进程,直到init进程为止。
linux控制台下输入ps -ef | grep 关键字
可以查看是否有相应的进程启动信息中包含关键字。
进程树
vi->bash->gnome-terminal-server->upstart --user->lightdm --session-child 12 19->lightdm->init auto noprompt
由pstree命令的得到的进程树
可以看出两种方法得到的进程树相同。
2、编写程序,首先使用fork系统调用,创建子进程。
在父进程中继续执行空循环操作;在子进程中调用exec打开vi编辑器。
//fork1.c
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main ()
{
pid_t fpid; //fpid表示fork函数返回的值
fpid=fork();
if (fpid < 0)
printf("error in fork!");
else if (fpid == 0) {
printf("Child process is running\n");
printf("Execve pid = %d ,parentpid = %d\n",getpid(),getppid());
printf("Execve uid = %d ,gid =%d\n",getuid(),getgid());
execlp("vi",0);
}
else {
while(1){
}
}
return 0;
}
运行结果,子进程打开了vi
然后在另外一个终端中
通过ps –Al
命令,查看vi进程及其父进程的运行状态
参数 | 意义 |
---|---|
F | 程序的flag |
S | 程序的运行状态 |
UID | 用户id |
PID | 进程id |
PPID | 当前进程的父进程id |
C | CPU资源使用的百分比 |
PRI | 优先级 |
NI | Nice值,负值表示高优先级,正值表示低优先级 |
ADDR | 指出程序在内存的哪个部分 |
SZ | 使用内存的大小 |
WCHAN | 程序是否仍在运行,若为-则正在运行 |
TTY | 启动进程的终端名 |
TIME | 进程使用CPU的总时间 |
CMD | 命令名 |
ps aux
命令
显示所有用户的进程,但该命令无法查看父进程的pid
参数 | 意义 |
---|---|
USER | 进程拥有者 |
PID | 进程id |
%CPU | 上次更新到现在的CPU时间占用百分比 |
%MEM | 进程使用的物理内存百分比 |
VSZ | 占用的虚拟内存大小 |
RSS | 占用的内存大小 |
TTY | 终端的次要装置号码 |
STAT | D代表不可中断 R代表正在执行 S代表静止状态 T代表暂停执行 Z代表僵死状态 |
START | 进程开始的时间 |
TIME | 进程占用CPU的时间 |
COMMAND | 命令名 |
top
命令
常用于监控linux的系统状况,显示系统运行时间和平均负载,系统现在进程运行情况,CPU状态,内存状态等信息。
通过内部命令P,使所有进程按照CPU占用率排序
3、使用fork系统调用,创建如下进程树,并使每个进程输出自己的ID和父进程的ID。
(csdn贴代码老出错,就不贴了)
去GitHub的直通车
第一个P1即为fork2进程,pid2878,父是2867,是bash
第二个P1是fork2建立的子进程,pid2879,父是2878
P2 pid 2880 父是P1 2879
P3 pid 2881 父是P1 2879
P4 pid 2882 父是P2 2880
P5 pid 2889 父是P2 2880
进程树
bash->fork2->P1->P3
->P2->P4
->P5
4、修改上述进程树中的进程,使得所有进程都循环输出自己的ID和父进程的ID。
(同理不贴代码了)
代码直通车
这里每次输出后都加了sleep(10)
,以及p1输出前加空格,方便观察和截图
终止p2进程,观察p1、p3、p4、p5进程的运行状态和其他相关参数有何改变。
采用kill -9
另开一个进程,使用kill -9 2962
命令后
可以看到进程p2没有了,p1、p3没有变化,但p4、p5(p2的子进程)依旧在,不过父进程变成了1540,也就是upstart --user
自己正常退出exit()
代码直通车
这里在p2的片段进行修改,在输出后加了exit(0)
printf("Node p2 pid %d, it's parent pid %d.\n",getpid(),getppid());
sleep(10);
printf("P2通过exit()自己正常退出\n");
exit(0);
结果相同
段错误退出
代码直通车
在p2的片段进行修改,使用空指针造成段错误
printf("Node p2 pid %d, it's parent pid %d.\n",getpid(),getppid());
sleep(10);
printf("P2发生段错误退出\n");
unsigned char *ptr = 0x00;
*ptr = 0x00;
可以看到,结果是进程p2消失,p1、p3无变化,p4、p5的父进程发生的更改,结果相同。
5、总结
本实验重点在于进程树的创建,我在写的时候在各进程的关系上绕晕了一段时间。
通过实验对fork函数和进程的理解更深了。
最后,本实验代码均上传至GitHub。
点这里直接进