目录
本人一直想找时间系统整理一下之前做过的一些实验,便于后续用到的时候可以尽快的使用,po出来也便于大家交流学习,有问题欢迎交流指正,与诸君共勉!
操作系统实验二,进程控制。
实验目的及要求
1. 理解进程的状态转换,了解进程控制函数:fork、wait/waitpid函数。
2. 掌握系统调用的简单编程。
3. 进一步掌握C语言程序的开发方法,阅读、调试C程序并编写简单的进程创建程序。
4. 通过有关进程控制的应用实例,深刻理解进程的管理过程。
实验环境
VMware虚拟机、CentOS操作系统
实验原理
1.进程状态命令
表1 Linux中的进程状态命令
ps命令 | ps输出中的标题 | ||
命令 | 作用 | 字段 | 解释 |
ps | 显示所有正在执行的进程 | PID | 进程标识号 |
ps-x | 显示所有程序,不以终端机来区分 | TTY | 开始这个进程的终端 |
ps-aux | 显示所有进程和其状态 | TIME | 进程的累计执行时间,以分和秒表示 |
ps aux|grep xxx | 显示进程名为xxx的进程的状态 | COMMAND | 正在执行的命令名 |
2.进程控制命令
(1)kill <进程标识符>,向进程发送终止信号,撤消进程。
(2)创建后台进程:在命令后输入后台命令符&,如$ sleep 50 & ,表示要创建一个睡眠时间为50秒的进程。
3. 进程控制相关的系统调用
(1)fork()。创建一个子进程,用它创建的子进程是fork调用者进程(即父进程)的复制品,即进程映象。除了进程标识符以及与进程特性有关的一些参数外,其它与父进程相同,与父进程共享文本段和打开的文件,并都受进程调度程序的调度。(一次调用两个返回结果)
如果创建进程失败,则fork()返回值为-1;如果创建进程成功,则在父进程中返回值是子进程号,子进程中返回的值是0。m=fork()。
(2)wait()。父进程处于阻塞(或等待)状态,等待子进程执行完成终止后继续工作(会令调用者阻塞直至某个子进程终止)。其返回值为子进程号。n=wait()。wait的返回值是终止进程的进程ID。
(3)waitpid()。等待一个或某个子进程退出函数。通常,父进程可以调用该函数,等待其所有子进程退出后才退出,保证所有任务顺利完成,具有指定性。
(4)exit()。子进程自我终止,释放所占资源,通知父进程可以删除自己。此时它的状态变成P_state=SZOMB。
(5)getpid()。获得进程的进程号,为正整数。p=getpid()。getppid()
实验内容与步骤
1. 在Linux下,top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。(用来看查看进程耗费cpu和内存的情况)[ctr+c退出]
2. 在Linux下,熟悉进程状态命令(ps)的使用;编写一些简单代码来观察各种情况下,Linux进程的状态,进一步理解进程的状态及转换机制。
图2 Linux中的进程状态转换
注:Linux下的TASK_RUNING状态包含了课本上的“运行”及“就绪”两种状体
通过ps命令,可以查看进程的状态:
R(TASK_RUNNING):可执行状态或运行状态
S(TASK_INTERRUPTIBLE):可中断阻塞状态,可响应中断、接收信号(如SIGKILL)
D( TASK_ UNINTERRUPTIBLE):不可中断阻塞状态,只能通过wake_up()函数明确唤醒时才能转换到可运行的就绪状态。
T( TASK_ STOPPED/ TASK_ TRACED):暂停状态或跟踪状态
Z( TASK_ DEAD/EXIT_ZOMBIE):退出状态,进程成为僵尸进程,此时,进程结束,但其父进程没有回收其剩余PCB资源,进程处于僵尸状态。
- 内容1:练习编写以下实例,来分析和理解Linux中进程的状态转换
a. 创建一个C程序,如run_status.c,运行一段长循环,使用gcc -o run_status run_status.c编译链接后,运行该程序;使用./run_status & ps ax | grep run_status命令查看程序状态,写出结果。
b.使用kill命令,向run_status进程发送SIGSTOP信号,并使用ps命令观察其状态(进入了T状态),如:kill –SIGSTOP 进程号。
c.创建一个C程序,如interruptiblie_status.c,让其睡眠30s
d.编译链接,后台运行该程序(后接&),并使用ps命令查看运行状态;在该状态下,使用kill –SIGKILL 进程号可强行终止该进程,写出运行结果。
e.创建一个C程序,如uninter_status.c,让其睡眠30s。使用kill -9 进程号命令后,用ps观察结果。说明:vfork也是进程创建函数,和fork函数的区别是:子进程创建后,父进程只能等到子进程调用exit或exec之后才能被调度执行;子进程和父进程共享空间。
f.创建一个C程序,如zombie_status.c,在其中创建一个子进程,并让子进程迅速结束,而父进程陷入阻塞。
g.编译链接,后台运行该程序,并使用ps命令查看运行状态(30s内)
3. 在Linux下,分析程序的功能与运行结果,熟悉Linux进程控制常用的系统调用。
(1)分析下列程序的功能与程序的运行结果。
#include <stdio.h>
main()
{ int p1,p2;
while((p1=fork())== -1);
if (p1==0)
putchar('b');
else
{ while((p2=fork( ))= = -1);
if(p2==0) putchar('c');
else putchar('a');
}
}
(2)分析使用wait()和exit()控制进程的程序功能与运行结果。
#include <stdio.h>
main()
{ int pid;
if(pid=fork())
{ wait();
printf("it is parent process\n");}
else
{ printf("it is child process\n");
exit();}
printf("it is end\n");
}
(3) 写出下列程序的功能,并分析程序的运行结果。
#include <stdio.h>
main()
{ int p1,p2,i;
while((p1=fork())== -1);
if (p1==0)
for(i=0;i<10;i++)
printf("daughter %d\n",i);
else
{
while((p2=fork())== -1);
if(p2= =0)
for(i=0;i<10;i++)
printf("son %d\n",i);
else
for(i=0;i<10;i++)
printf("parent %d\n",i);
}
}
(4)分析并完善下列程序。程序的功能是:输入两个整数并求和输出,然后创建一个子进程,当进程调度程序调度到父进程或子进程时将输出不同的信息。
#include <stdio.h>
main()
{ int i,j,k,sum;
scanf("%d%d",&j,&k);
sum=j+k;
printf("sum=%d \n",sum);
while( (i=fork()) ==-1 )
{ printf("i=%d\n",i); }
if( i=getpid() )
printf("it is parent process!\n");
else
printf("it is child process!\n");
}
(5)分析并完善下列程序。程序的功能是:如果父进程要通过建立子进程在同一显示器上分别循环显示“Parents”和“Children”,循环次数由n决定。
#include <stdio.h>
main( )
{ int pid,n; n=1;
if(( fork() )!=0)
While(n<10)
{ printf("%d",n++);
printf("Parents"); }
else
While(n<10)
{
printf("Children"); }
}
4. 线程异步并发实验
step1:编写一个c语言程序,初始化一个count变量为1;使用pthread_create函数创建两个线程,每个线程对count加1之后,显示“I am son, count=?”或“I am daughter, count=?”,?使用count值代替。父进程对count加之后,显示“I am father, count=?”,?使用count值替代。最后,父进程使用pthread_join等待两个线程结束后退出。
step2:编译后,运行该程序,分析屏幕上显示结果的顺序性,直至出现不一样的情况为止,观察每行打印结果中count的值。(注意,需要链接librt.so库,编译如:gcc -o tst_thread tst_thread.c -lrt)-lpthread -pthread
实验结果与分析
1.实例一
编写一个c程序run_status.c,如图3。
图3 创建c程序run_status.c
使用gcc -o run_status run_status.c编译链接,如图4。
图4 编译run_status.c
运行程序,使用./run_status & ps ax | grep run_status命令查看程序状态,如图5。
图5 运行程序后查看程序状态
结果分析:如图5所示,./run_status程序有一个pid为4465的进程处于T状态(暂停状态),该进程实际使CPU运行的时间为8s,pid为4480的进程状态为R状态(正在运行或在运行队列中等待)。
使run_status颜色高亮的进程pid为4482,处于S状态(休眠状态)。
2.实例二
使用kill命令,向run_status进程发送SIGSTOP信号,并使用ps命令观察其状态(进入了T状态),如图10,pid为4575的进程已进入T状态(暂停状态)。
图10使用kill命令向进程发送SIGSTOP信号
分析:观察到pid为4575的进程已进入T状态(暂停状态)。
3.实例三
使用kill命令,向run_status进程发送SIGCONT信号,并使用ps命令观察其状态(恢复到R状态),如图11,pid为4575的进程已进入R状态。
图11 使用kill命令向进程发送SIGCONT信号
4.实例四
创建一个c程序interruptible_statis.c,让其睡眠30s,如图12。
图12 创建c程序interruptible_statis.c
分析:该程序使终端休眠30秒。
5.实例五
图13 编译interruptible_statis.c 后台运行
图14 ps命令查看运行状态
图15 向后台运行的进程发送SIGKILL信号强行终止进程
分析:如图15,使用kill -SIGKILL 强行终止后台运行的./interruptible_status进程。观察到该进程killed(被杀死)。
6.实例六
创建一个C程序,uninter_status.c,如图16。
使用kill -9 进程号命令后,用ps观察结果,如图17。可观察到该进程被杀死。
图16 创建c程序uninter_status.c
图17 kill -9 进程号命令后,用ps观察结果
7.实例七
创建一个c语言程序,如zombie_status.c,在其中创建一个子进程,并让子进程迅速结束,而父进程陷入阻塞,如图18。
图18 创建c程序zombie_status.c
8.实例八
编译链接,后台运行程序zombie_status.c,并使用ps命令查看运行状态(30s内), 如图19。
图19 后台运行程序 ps查看运行状态图
分析状态:如图,可观察到pid为20552的程序为defunct状态。是一个早已死亡的僵尸进程。
9. 选做题
(1)
图20 选做题1代码文件
程序功能:程序创造子进程,根据fork返回的值输出不同字母,可判断当前进程是父进程还是子进程。当进程调度程序调度到父进程或子进程时将输出不同的信息
运行结果:
图21 选做题1运行结果
(2)
图22 选做题2代码文件
程序功能:如果fork返回0,在子进程中,fork返回新创建子进程的进程id,在父进程中。当进程调度程序调度到父进程或子进程时将输出不同的信息。
运行结果:
图23 选做题2运行结果
(3)
图24 选做题3代码文件
程序功能:创建两个进程,当进程调度程序调度到父进程或子进程时将输出不同的信息。
运行结果:
图25选做题3运行结果
(4)
图26 选做题4代码文件
程序功能:输入两个整数并求和输出,然后创建一个子进程,当进程调度程序调度到父进程或子进程时将输出不同的信息。
运行结果:
图27 选做题4运行结果
(5) 分析并完善下列程序。
图28 选做题5代码文件
程序功能:如果父进程要通过建立子进程在同一显示器上分别循环显示“Parents”和“Children”,循环次数由n决定。
运行结果:
图29 选做题5运行结果
10. 线程异步并发实验
编写一个c语言程序,如图
图30 test44.c
输入指令gcc test44.c -o test44 -lrt -pthread进行编译,如图
图31 编译test44.c
编译后运行该程序,如图
图32 运行teste44
如图所示,线程异步并发程序中,parent、son和daughter中的count不是独立的,先是在parent中count加1变为2,然后son中count又加1变为3,然后daughter中count又加1变为4。
总结
父进程和子进程二者并不共享地址空间,两个是单独的进程,继承以后二者不再有关联,子进程单独运行。同一进程中的所有线程共享所在进程的地址空间和全部资源,但线程间都相互独立的并发执行。
实验收获及体会
本次实验中通过对于实验代码的编写,我巩固了使用Linux系统编辑、编译运行c语言程序,理解了进程的状态转换,了解了进程控制函数:fork、wait/waitpid函数,并且掌握了系统调用的简单编程。
通过对实验代码运行结果的观察,我更加理解了进程控制的应用,深刻理解了进程的管理过程,在实验过程中也再一次巩固了我对于Linux系统常用指令的使用,这将为我今后操作系统的学习打下牢固的基础。
实验结果往往能给我更加深刻的印象以及对课本理论知识更为深刻的理解,今后的理论知识学习过程中也应该注重动手实践。