实验三:进程控制
红体字依然是懒懒的小白必看内容~~
【实验前的准备】
先来点**必读材料**
:
一、进程的控制
进程因创建而存在,因执行完成或异常原因而终止.在进程的生命周期中,进程在内存中有三种基本状态:
**就绪,执行,阻塞**
.进程状态的转换是通过进程控制原语来实现的。Linux操作系统提供了相应功能的系统调用及命令,来实现用户层的进程控制。
二、相关命令:
(1)睡眠指定时间
执行格式:#sleep x,x为指定睡眠的秒数。
(2)结束或终止进程 kill
执行格式: #kill [-9] PID (PID为利用ps命令所查出的process ID)
(3)查看正在background中执行的process
执行格式:#jobs
(4)用户在终端输入Linux命令时,对应的shell通常会建立子进程来运行该命令。通过ps命令可以查看用户空间的当前进程。
执行格式: #ps [-auf]
-a 列出当前终端上启动的所有进程;
-u 按用户名和启动时间的顺序来显示进程;
-f 以全格式列出
三、系统调用:
1、exec( )系列:
如果exec( )调用成功,调用进程将被覆盖,然后从新程序的入口开始执行。exec( )没有建立一个与调用进程并发的子进程,而是用**新进程取代了原来进程**
。所以exec( )调用成功后,没有任何数据返回。
2、exec( )和fork( )联合使用
系统调用exec和fork( )联合使用能为程序开发提供有力支持。用fork( )建立子进程,然后在子进程中使用exec( ),这样就实现了父进程与一个与它完全不同子进程的并发执行。
更多关于exec()系列函数,请见这位大佬的博文:
https://blog.csdn.net/amoscykl/article/details/80354052?utm_source=app&app_version=5.3.0&code=app_1562916241&uLinkId=usr1mkqgl919blen
3、wait()
等待子进程运行结束。如果子进程没有完成,父进程一直等待
。
4、sleep()
睡眠指定时间。该函数使得当前进程自我阻塞second秒
,由执行态转换成阻塞态,直到系统唤醒。
5、exit()
终止进程的执行
。为了及时回收进程所占用的资源并减少父进程的干预,LINUX/LINUX利用exit( )来实现进程的自我终止,通常父进程在创建子进程时,应在进程的末尾安排一条exit( ),使子进程自我终止。exit(0)表示进程正常终止,exit(1)表示进程运行有错,异常终止。
掌握了以上知识点,就可以开始实验了
~
【实验目的】
1、了解进程创建后对进程控制的系统调用,可实现对进程的有效控制
2、掌握进程的睡眠、同步、撤消等进程控制方法
【实验内容】:
0、阅读实验相关资料。
1、通过相关命令,对进程的状态进行控制。
2、编写程序,使用fork( )创建一个子进程。使用相关的系统调用控制进程的状态。观察并分析多进程的执行次序及状态转换。
【实验步骤】:
1、参考程序:
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main( )
{
int pid;
pid=fork( ); /*创建子进程*/
switch(pid)
{
case -1: /*创建失败*/
printf("fork fail!\n");
exit(1);
case 0:/*子进程*/
printf("Is son:\n");
execl("/bin/ls","ls","-l",NULL);
printf("exec fail!\n");
exit(1);
default:/*父进程*/
printf("ls parent:\n");
while(1) sleep(1);
exit(0);
}
return 0;
}
2、运行结果:
yzy@yzy-virtual-machine:~/123$ gcc fork_exec.c -o def
yzy@yzy-virtual-machine:~/123$ ./def&
[2] 2318
yzy@yzy-virtual-machine:~/123$ ls parent:
Is son:
总用量 24
-rwxrwxr-x 1 yzy yzy 16992 4月 3 10:12 def
-rw-rw-r-- 1 yzy yzy 502 4月 3 10:09 fork_exec.c
3、解释:子进程用exec( )装入命令ls,exec( )后,子进程的代码被ls的代码取代,这时子进程的PC指向ls的第1条语句,开始执行ls的命令代码。
4、用 jobs命令查看后台运行的process 。
yzy@yzy-virtual-machine:~/123$ jobs
[1]+ 运行中 ./def &
5、用ps 命令显示当前终端上启动的所有进程
yzy@yzy-virtual-machine:~/123$ ps -af
UID PID PPID C STIME TTY TIME CMD
yzy 1612 1609 1 10:08 tty2 00:00:11 /usr/lib/xorg/Xorg vt2 -disp
yzy 1626 1609 0 10:08 tty2 00:00:00 /usr/libexec/gnome-session-b
yzy 2422 2416 0 10:18 pts/0 00:00:00 ./def
yzy 2423 2422 0 10:18 pts/0 00:00:00 [ls] <defunct>
yzy 2425 2416 0 10:20 pts/0 00:00:00 ps -af
解释:倒数第二行,[ls] defunct 说明进程”ls”是一个僵死进程
。父进程创建一个子进程后,可以用wait()等待回收其子进程的资源,也可以正常终止后由系统回收其子进程的资源。
6、用kill命令直接杀死该子进程。
yzy@yzy-virtual-machine:~/123$ kill -9 2423
yzy@yzy-virtual-machine:~/123$ ps -af
UID PID PPID C STIME TTY TIME CMD
yzy 1612 1609 1 10:08 tty2 00:00:12 /usr/lib/xorg/Xorg vt2 -disp
yzy 1626 1609 0 10:08 tty2 00:00:00 /usr/libexec/gnome-session-b
yzy 2422 2416 0 10:18 pts/0 00:00:00 ./def
yzy 2423 2422 0 10:18 pts/0 00:00:00 [ls] <defunct>
yzy 2442 2416 0 10:25 pts/0 00:00:00 ps -af
解释:未能成功,因为父进程还没结束
。
7、kill命令杀死父进程之后,成功。
yzy@yzy-virtual-machine:~/123$ kill -9 2422
yzy@yzy-virtual-machine:~/123$ ps -af
UID PID PPID C STIME TTY TIME CMD
yzy 1612 1609 1 10:08 tty2 00:00:13 /usr/lib/xorg/Xorg vt2 -disp
yzy 1626 1609 0 10:08 tty2 00:00:00 /usr/libexec/gnome-session-b
yzy 2459 2416 0 10:27 pts/0 00:00:00 ps -af
[1]+ 已杀死 ./def
解释:但是如果父子进程都异常终止,则shell进程将回收其资源。Init进程回收所有僵死进程资源。
8、修改程序fork_ececl.c,在父进程执行” while(1)”之前,添加代码”wait(0);”。在后台执行该程序。显示当前终端上启动的所有进程。
yzy@yzy-virtual-machine:~/123$ Is son:
总用量 24
-rwxrwxr-x 1 yzy yzy 17032 4月 3 11:03 def
-rw-rw-r-- 1 yzy yzy 530 4月 3 11:03 fork_exec.c
ls parent:
解释:子进程结束后,它的父进程在等待(调用wait函数)它,所以Is son先显示。Wait函数:若未找到处于“僵死状态”的子进程,则调用进程便在可被中断的优先级上睡眠,等待其子进程发来软中断信号时被唤醒。
9、修改以上程序,在子进程执行”printf(“Is son:\n”);”之前添加代码“sleep(1);”。(若父进程先输出,则在父进程执行printf(“ls parent:\n”);之前添加代码“sleep(1);”)观察多进程的执行序列,解释原因。
yzy@yzy-virtual-machine:~/123$ ls parent:
Is son:
总用量 24
-rwxrwxr-x 1 yzy yzy 16992 4月 3 11:16 def
-rw-rw-r-- 1 yzy yzy 531 4月 3 11:16 fork_exec.c
解释:sleep函数:second为指定睡眠的秒数。该函数使得当前进程自我阻塞second秒,由执行态转换成阻塞态,直到系统唤醒。
多次执行,都为上述结果,屏幕输出is parent后,停顿约1秒后才显示后续内容。
【实验感想】:
(1)可执行文件加载时进行了哪些处理?参考程序中,什么时候执行语句”printf(“exec fail!\n”);”?
经过这些处理:C源程序一>编译预处理一>编译一>优化程序一>汇编程序一>链接程序一>可执行文件。
execl("/bin/ls",“ls”,"-l",NULL);在这个语句中,“bin/ls”为文件目录路径;“ls”、“-l”代表执行文件传递过去的参数;Null为结束符。。如果exec( )调用成功,调用进程将被覆盖,然后从新程序的入口开始执行。
若execl()没有调用成功,失败原因记录在error中,执行下一条语句:printf("exec fail!\n"
)
(2)实验指导中的第5步,wait( )是如何实现进程同步的?
首先,
程序在调用fork()那里创建了一个子进程后,马上调用wait(),使父进程在子进程调用之前一直处于睡眠状态,这样就使子进程先运行,子进程运行exec()装入命令后,然后调用wait(0),使子进程和父进程并发执行,实现进程同步
。
(3)实验指导中的第6步,sleep(1)为什么能导致进程切换?
Sleep函数使得当前进程自我阻塞1秒,由执行态转换成阻塞态,所以从正在运行的进程中收回处理器,让等待运行的就绪态的进程来占有处理器运行。等中断处理完后,再继续恢复原进程处理
。
喜欢的朋友可以留下你的赞哦
~~~