计算机组成原理与操作系统-实验指导书 联系客服

发布时间 : 星期五 文章计算机组成原理与操作系统-实验指导书更新完毕开始阅读e4a974f3c77da26925c5b0bf

《操作系统原理及应用》实验指导书

实验三 进程观察实验(一):多进程环境

实验目的

1、掌握进程的概念.认识进程并发执行的实质.

2、能够使用系统调用完成进程的创建,形成多进程并发执行的环境.

实验内容

1 、通过相关命令,认识Linux是一个多任务多进程操作系统。观察当前终端上启动的所有进程,列出

系统中所有进程,显示系统中的进程状态。

2、编写程序,使用fork( )创建两个子进程。观察并分析在程序运行过程中的进程状态变化。

实验基础

一、LINUX进程

引入进程概念,是为了描述多道程序的并发执行。因此用进程来描述程序的一次执行。为了执行一个程序,首先要创建进程。资源足够时,os为进程分配内存资源。虚存中的进程映像,包括了进程所需内存的全部内容:程序和相关数据;操作系统利用PCB来控制和管理进程,其中为每个进程赋予惟一的进程标识符就放在PCB中;进程执行的局部变量放在栈中;还有共享存储区。

进程是资源分配的基本单位,也是系统调度的基本单位。多进程并发执行,在单处理器中,就是多个进程轮流占用CPU,交替执行。哪个进程占用CPU是操作系统调度的结果。

Linux进程树 引导过程:首先,计算机电源打开,进行加电自检(POST);然后寻找引导程序:从磁盘0号块读出引导程序装入内存,创建了第一个进程(进程0),再由引导程序从硬盘根目录下把/LNIX操作系统映像安装到内存,创建了它的第一个子进程,即init(进程1),进程1成为系统其他所有进程的祖先进程。

在UNIX中经常要发生进程在内存与磁盘之间的转换,称为进程的换出换进。UNIX中的0进程也称为交换进程(swapper),它的任务就是把进程换进或换出,是系统中唯一的核心态进程。在系统初始化交换进程就开始工作,它执行sched程序来完成换进换出的工作。Init进程决不会终止。它是一个普通的用户进程,但它以超级用户特权运行。

登录:首先,init确信对于终端连接(或控制台)有一个对应的getty程序。getty在终端上侦听并且等待用户通告他已准备好登录(这通常意味着用户必须键入些什么)。当它注意到一个用户,getty输出一段欢迎消息(存储于/etc/issue),提示输入用户名,并且最终运行login程序。login将用户名作为参数,提示用户输入口令。如果不匹配,它就退出并终止该进程(也许是在给用户另一个输入用户名和口令的机会以后)。init注意到这个进程终止以后,就开始为该终端运行一个新的getty程序。如果这些都匹配的话,login开始运行为该用户配置的shell,等待用户命令的输入;并且自动装载日期,安装文件系统,启动假脱机,初始化网络服务,运行保护程序,清除系统临时区和用户临时区文件。

执行命令:进程1负责为每个终端建立一个进程,执行shell解释程序。shell解释程序分析输入的命令,找到相应的命令执行文件,并为之建立一个子进程来执行这个命令,一旦命令执行完毕,相应的子进程即被撤销。

在Linux系统中,进程0为交换进程,进程1为init初始化进程。只有0进程是在系统引导时

4

《操作系统原理及应用》实验指导书

被创建的,在系统初启时由0进程创建1进程,以后0进程变成对换进程,1进程成为系统中的始祖进程。

Linux系统中所有进程都是相互联系的。除了初始化进程外,所有进程都有一个父进程。新进程不是被创建,而是被复制,或者从以前的进程复制而来。Linux系统中所有的进程都是由一个进程号为1的init进程衍生而来的。而我们在Shell下执行程序启动的进程则是Shell进程的子进程,当然我们启动的进程可以再启动自己的子进程。这样形成了一棵进程树,每个进程都是树中的一个节点,其中树的根是init。一个进程可以按自己的意愿或受外部事件的影响而请求终止,进程终止时由其父进程作善后处理。

Linux利用fork( )为每个终端创建一个子进程为用户服务,如等待用户登录、执行SHELL命令解释程序等,每个终端进程又可利用fork( )来创建其子进程,从而形成一棵进程树。可以说,系统中除0进程外的所有进程都是用fork( )创建的。

二、所涉及的命令

(1)查看系统目前的进程 ps 执行格式: # ps [-auf]

-a 列出当前终端上启动的所有进程;

-t 列出指定终端上启动的所有进程; 如 ps –t pts/1 -u 列出指定用户的所有进程; 如 ps –u lily

-e列出系统中所有进程;-f 以full格式列出; -l以long格式列出;

例:ps -af|grep apa 找出当前终端上启动的进程中所有名称中带有\串的进程

其中,UID表示该进程的创建用户号,PID表示该进程号,PPID表示该进程的父进程号, CMD表示产生该进程的命令。 tty值为“?”表示是守护进程。

(2)显示系统中的进程状态

执行格式: # top 每隔5s统计显示一次系统中的进程状态 # top -q 不断地更新、显示系统中的进程状态

第一行显示的项目依次为当前时间、系统启动时间、当前系统登录用户数目、平均负载。 第二行为进程情况,依次为进程总数、休眠进程数、运行进程数、僵死进程数、终止进程数。 第三行为CPU状态,依次为用户占用、系统占用、优先进程占用、闲置进程占用。

第四行为内存状态,依次为平均可用内存、已用内存、空闲内存、共享内存、缓存使用内存。 第五行为交换状态,依次为平均可用交换容量、已用容量、闲置容量、高速缓存容量。 PID 每个进程的ID。

PPID 每个进程的父进程ID。 UID 每个进程所有者的UID 。 USER 每个进程所有者的用户名。 PRI 每个进程的优先级别。 NI 该进程的优先级值。

SIZE 该进程的代码大小加上数据大小再加上堆栈空间大小的总数。单位是KB。 TSIZE 该进程的代码大小。对于内核进程这是一个很奇怪的值。 DSIZE 数据和堆栈的大小。 TRS 文本驻留大小。

D 被标记为“不干净”的页项目。

LIB 使用的库页的大小。对于ELF进程没有作用。 RSS 该进程占用的物理内存的总数量,单位是KB。 SHARE 该进程使用共享内存的数量。

STAT 该进程的状态。其中S代表休眠状态;D代表不可中断的休眠状态;R代表运行状态;Z代表僵死状态;T代表停止或跟踪状态。

TIME 该进程自启动以来所占用的总CPU时间。如果进入的是累计模式,那么该时间还包括这个进程子进程所占用的时间。且标题会变成CTIME。

%CPU 该进程自最近一次刷新以来所占用的CPU时间和总时间的百分比。 %MEM 该进程占用的物理内存占总内存的百分比。

5

《操作系统原理及应用》实验指导书

COMMAND 该进程的命令名称,如果一行显示不下,则会进行截取。内存中的进程会有一个完整的命令行。

按\停止查看

(7)以树状图显示进程 pstree

例: pstree -h 列出进程树并高亮标出当前进程 此命令可展示出系统中的进程树结构。

其中,init是1号进程,系统所有进程都是它派生的。 (8)监视虚拟内存 vmstat

vmstat对系统的虚拟内存、进程、CPU活动进行监视,同时它也对磁盘和forks和vforks操作的个数进行汇总。

不足是:vmstat不能对某个进程进行深入分析,它仅是一对系统的整体情况进行分析。例如: # vmstat

procs memory swap io system cpu

r b w swpd free buff cache si so bi bo in cs us sy id 0 0 0 7180 1852 56092 48400 0 0 6 5 24 8 0 0 18 其中: Procs

r: 等待运行的进程数 b: 处在非中断睡眠状态的进程数 w: 被交换出去的可运行的进程数。 Memory

swpd: 虚拟内存使用情况,单位:KB free: 空闲的内存,单位KB buff: 被用来做为缓存的内存数,单位:KB Swap

si: 从磁盘交换到内存的交换页数量,单位:KB/秒 so: 从内存交换到磁盘的交换页数量,单位:KB/秒 IO

bi: 发送到块设备的块数,单位:块/秒 bo: 从块设备接收到的块数,单位:块/秒 System

in: 每秒的中断数,包括时钟中断 cs: 每秒的环境(上下文)切换次数 CPU 按 CPU 的总使用百分比来显示

us: CPU 使用时间 sy: CPU 系统使用时间 id: 闲置时间

以下两个命令可用于程序的跟踪观察。

(9)监视用户空间程序发出的全部系统调用 strace

strace 还能显示调用的参数,以及用符号方式表示的返回值。

strace 从内核中接收信息,所以一个程序无论是否按调试方式编译(gcc -g)或是否被去掉

了调试信息,都可以被跟踪。

执行格式: strace [-tTeo] executable-program-name -t : 用来显示调用发生的时间 -T : 显示调用花费的时间 -e : 限定被跟踪的调用类型

-o : 将输出重定向到一个文件中

类似命令:ltrace [-fiS] executable-program-name

(10)ltrace :解释并记录执行程序调用的动态链接库以及进程接收到的信号。也解释并打印程序执行的系统调用。

-f 跟踪子进程。

-i 库调用时打印指令指针。 -S 显示系统调用和库调用

可用ltrace -f -i -S ./executable-file-name查看指定程序的执行过程。

三、所涉及的系统调用

1、fork( ) 创建一个新进程。 系统调用格式: pid=fork( )

6

《操作系统原理及应用》实验指导书

PC 函数原型: int fork( ) fork( )返回值意义如下:

0:在子进程中,pid变量保存的fork( )返回值为0,表示当前进程是子进程。

>0:在父进程中,pid变量保存的fork( )返回值为子进程的id值(进程唯一标识符)。 -1:创建失败。

如果fork( )调用成功,它向父进程返回子进程的PID,并向子进程返回0,即fork( )被调用了一次,但返回了两次。此时OS在内存中建立一个新进程,所建的新进程是父进程(parent process)的副本,称为子进程(child process)。子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文。父进程与子进程并发执行。

核心为fork( )完成以下操作:

(1)为新进程分配一进程表项和进程标识符

进入fork( )后,核心检查系统是否有足够的资源来建立一个新进程。若资源不足,则fork( )系统调用失败;否则,核心为新进程分配一进程表项和唯一的进程标识符。

(2)检查同时运行的进程数目

超过预先规定的最大数目时,fork( )系统调用失败。 (3)拷贝进程表项中的数据

将父进程的当前目录和所有已打开的数据拷贝到子进程表项中,并置进程的状态为“创建”状态。

(4)子进程继承父进程的所有文件

对父进程当前目录和所有已打开的文件表项中的引用计数加1。 (5)为子进程创建进程上、下文

进程创建结束,设子进程状态为“内存中就绪”并返回子进程的标识符。 (6)子进程执行

虽然父进程与子进程程序完全相同,但每个进程都有自己的程序计数器PC(注意子进程的PC开始位置),然后根据pid变量保存的fork( )返回值的不同,执行了不同的分支语句。

例:

…..

pid=fork( );

if (! pid)

printf(\

else if (pid>0)

printf(\

else

printf(\

…… fork( )调用前

fork( )调用后

….. ….. pid=fork( ); pid=fork( ); if (! pid) if (! pid) printf(\ printf(\ else if (pid>0) else if (pid>0) printf(\ printf(\ else else printf(\ printf(\ …… …… PC PC (2) 获取进程的PID

得到当前进程的PID。函数原型: int getpid()

得到当前进程的父进程的PID。函数原型: int getppid() (3)system():在程序中运行一个命令

7