李许增16281042
操作系统arch Linux
单步ps命令选择得到的进程树和用pstree命令得到的进程树相同。
ps -f -C name 命令为筛选指定名称进程的信息;
ps -p 进程号 -o comm= 为查找pid对应进程的名称;
ps -p -s 进程号 命令为查找指定进程号的进程树。
#include
#include
int main()
{
pid_t fork_pid;//fork_pid为fork函数返回值
fork_pid = fork();
if(fork_pid < 0)//当返回值为负值时表示出现错误
{
printf("fork error");
}
else if(fork_pid == 0)//当返回值为0时表示创建的子进程在运行
{
printf("我是子进程,我的pid为:%d\n",getpid());
if((execlp("vi","vi","/home/os-2019/test",NULL))<0)//注意execlp参数使用
printf("execlp error\n");
}
else//当返回值为其他正值时表示父进程在运行
{
printf("我是父进程,我的pid为:%d\n",getpid());
while(1){};
}
return 0;
}
USER: 进程拥有者
PID: 进程pid
%CPU: 占用的 CPU 使用率
%MEM: 占用的内存使用率
VSZ: 占用的虚拟内存大小
RSS: 占用的内存大小
TTY: 终端的次要装置号码 (minor device number of tty)
STAT: 该进程的状态,linux的进程有以下状态:
1. D :不可中断 Uninterruptible(usually IO)
2. R :正在运行,或在队列中的进程
3. S :处于休眠状态
4. T :停止或被追踪
5. Z :僵尸进程
6. W:进入内存交换(从内核2.6开始无效)
7. X :死掉的进程
8. < :高优先级
9. n:低优先级
10. s: 包含子进程
11. “+”: 位于后台的进程组
START: 进程开始时间
TIME: 执行的时间
COMMAND:对应执行的指令
UID:用户ID(User ID)
PPID:父进程pid
S:进程或内核线程的状态:
O:不存在
A:活动
W:已交换
I:空闲(等待启动)
Z:已取消
T:已停止
S:正在休眠
R:正在运行
C:(-f、l 和 -l 标志)每次系统时钟周期和发现线程或进程需要运行时增加进程或线程的 CPU 利用率。调度程序通过每秒将该值除以2一次来使其衰减。对于sched_other策略,CPU 利用率用于确定进程调度优先级。如果值较大,那么表示一个将耗用大量 CPU 资源的进程,该进程的优先级将更低;如果值较小,那么表示一个要执行大量 I/O 操作的进程,其优先级将更高。
PRI:(-l 和 l 标志)进程或内核线程的优先级;数字越大优先级越低。
WCHAN:(-l 标志)进程或内核线程为之等待或休眠的事件。对于内核线程,如果内核线程正在运行,该字段为空。 对于进程,如果只有一个内核线程正在休眠,等待通道定义为该休眠内核线程的等待通道;否则显示一个星号。
NI:(-l 和 l 标志)为 sched other 策略计算优先级中使用的细调值。
ADDR:通常情况下,(-l 和 l 标志)包含 进程栈的段号;如果为内核进程,那么为预处理数据区的地址。
SZ:(-l 和 l 标志)进程的核心映像大小(以 1 KB 为单位)。
TIME:(所有标志)进程的运行时间总和。如果运行时间达到 100 分钟,以 mm:ss 或 mmmm:ss 格式显示时间,这与使用 -o time 标志时的显示格式不同。
从得到的结果可以看出父进程2_fork在进行不断循环cpu占用率高达99.8%。
#include
#include
int main()
{
pid_t fpid = fork();
if(fpid == 0)
{
printf("我是子进程 P3 ,我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
}
else
{
printf("我是父进程 P1 ,我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
fpid = fork();
if(fpid == 0)
{
printf("我是子进程 P2 ,我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
fpid = fork();
if(fpid == 0)
{
printf("我是孙子进程 P4, 我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
}
else
{
fpid = fork();
if(fpid == 0)
{
printf("我是孙子进程 P5 ,我的pid为:%d,ppid为:%d\n",getpid(),getppid());
}
else
{
}
}
}
else
{
}
}
sleep(20);
return 0;
}
根据pstree命令查看进程得到结果与题目要求相同。
一般来说,在 fork() 之后是父进程先执行还是子进程先执行是不确定的。这取决于内核所使用的调度算法。(然而实验多次并为出现次序改变)。
#include
#include
#include
int main()
{
pid_t fpid = fork();
if(fpid == 0)
{
while(1){
printf("我是子进程 P3 ,我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
sleep(2);
}
}
else
{
fpid = fork();
if(fpid == 0)
{
fpid = fork();
if(fpid == 0)
{
while(1){
printf("我是孙子进程 P4, 我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
sleep(2);
}
}
else
{
fpid = fork();
if(fpid == 0)
{
while(1){
printf("我是孙子进程 P5 ,我的pid为:%d,ppid为:%d\n",getpid(),getppid());
sleep(2);
}
}
else
{
}
}
while(1){
printf("我是子进程 P2 ,我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
sleep(2);
//正常退出exit(1);
//段错误方式: int *ptr = (int *)0;*ptr = 100;
}
}
else
{
}
while(1){
printf("我是父进程 P1 ,我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
sleep(2);
}
}
sleep(20);
return 0;
}
P1正常运行,从ps命令可以看出P2进程变为僵尸进程(stat状态为z,zombie),其子进程P4,P5仍在运行,但是变为pid为1的子进程,相对于P1的进程树不显示P4,P5。
修改代码:
while(1){
printf("我是子进程 P2 ,我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
sleep(2);
exit(1)
}
P1正常运行,同使用kill命令杀死进程相同P2进程变为僵尸进程(stat状态为z,zombie),其子进程P4,P5仍在运行,但是变为pid为1的子进程,相对于P1的进程树不显示P4,P5。
段错误产生原因:
1、访问不存在的内存地址;
2、访问系统保护的内存地址
3、访问只读的内存地址
4、栈溢出
这里我采用访问系统保护的地址使段错误产生:
while(1){
printf("我是子进程 P2 ,我的pid为:%d,我的ppid为:%d\n",getpid(),getppid());
sleep(2);
int *ptr = (int *)0;
*ptr = 100;
}
P1正常运行,同使用前两种方式结束P2进程相同,P2进程变为僵尸进程(stat状态为z,zombie),其子进程P4,P5仍在运行但是变为pid为1的子进程,相对于P1的进程树不显示P4,P5。