《操作系统实验报告_实验四.pdf》由会员分享,可在线阅读,更多相关《操作系统实验报告_实验四.pdf(8页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、-实验四:进程管理二 实验容:1编写一个程序,打印进程的如下信息:进程标识符,父进程标识符,真实用户 ID,有效用户 ID,真实用户组 ID,有效用户组 ID。并分析真实用户 ID 和有效用户 ID 的区别。源代码及结果:真实用户 ID 和有效用户 ID 的区别:真实用户 ID:这个 ID 就是我们登陆 uni*系统时的身份 ID。有效用户 ID:定义了操作者的权限。有效用户 ID 是进程的属性,决定了该进程对文件的权限。2阅读如下程序,编译并运行,分析进程执行过程的时间消耗总共消耗的时间和CPU 消耗的时间,并解释执行结果。再编写一个计算密集型的程序替代 grep,比拟两次时间的花销。注释程
2、序主要语句。/*process using time */#include#include#include#include#include voidtime_print(char*,clock_t);int main(void)/取得进程运行相关的时间 clock_tstart,end;structtmst_start,t_end;start=times(&t_start);system(grep the/usr/doc/*/*/dev/null 2/dev/null);/*mand/dev/null 的作用是将是 mand 命令的标准输出丢弃,而标准错误输出还是在屏幕上。一般来讲标准输出和标
3、准错误输出都是屏幕,因此错误信息还是会在屏幕上输出。/dev/null 2/dev/null 标准输出与标准错误输出都会被丢弃*/-/0 1 2 标准输入标准输出错误输出/将信息放到该文件 null 中 end=times(&t_end);time_print(elapsed,end-start);puts(parent times);time_print(tuser CPU,t_end.tms_utime);time_print(tsys CPU,t_end.tms_stime);puts(child times);time_print(tuser CPU,t_end.tms_cutime)
4、;time_print(tsys CPU,t_end.tms_cstime);e*it(E*IT_SUCCESS);voidtime_print(char*str,clock_t time)longtps=sysconf(_SC_CLK_TCK);/*函数 sysconf()的作用为将时钟滴答数转化为秒数,_SC_CLK_TCK 为定义每秒钟有多少个滴答的宏*/printf(%s:%6.2f secsn,str,(float)time/tps);程序运行结果:因为该程序计算量很小,故消耗的时间比拟少,CPU 消耗时间均为 0.00secs 缺乏为奇。而进程的执行时间等于用户 CPU 时间和系统
5、 CPU 时间加从硬盘读取数据时间之和。密集型的程序替代 grep:更改为计算密集型的之后就较容易观察出消耗时间的差异。3阅读以下程序,编译并屡次运行,观察执行输出次序,说明次序一样或不同的原因;观察进程 ID,分析进程 ID 的分配规律。总结 fork()的使用方法。注释程序主要语句。/*fork usage */#include#include#include-int main(void)pid_t child;if(child=fork()=-1)perror(fork);e*it(E*IT_FAILURE);else if(child=0)puts(in child);printf(t
6、childpid=%dn,getpid();printf(tchildppid=%dn,getppid();e*it(E*IT_SUCCESS);else puts(in parent);printf(tparentpid=%dn,getpid();printf(tparentppid=%dn,getppid();e*it(E*IT_SUCCESS);程序运行结果:?创立进程 ID 开场时一般随机分配,但假设屡次运行,或创立子进程时,会顺序分配存。此外,当父进程完毕时,子进程尚未完毕,则子进程的父进程 ID 变为 1。fork()函数的实质是一个系统调用(和 write 函数类似),其作用是创
7、立一个新的进程,当一个进程调用它,完成后就出现两个几乎一模一样的进程,其中由 fork()创立的新进程被称为子进程,而原来的进程称为父进程。子进程是父进程的一个拷贝,即子进程从父进程得到了数据段和堆栈的拷贝,这些需要分配新的存;而对于只读的代码段,通常使用共享存方式进展。4阅读以下程序,编译并运行,等待或者按C,分别观察执行结果并分析,注释程序主要语句。flag 有什么作用?通过实验说明。/*usage of kill,signal,wait */#include-#include#include#include int flag;void stop();/自定义函数,使 flag=0,供 s
8、ignal 调用 int main(void)int pid1,pid2;signal(3,stop);/signal()依参数 3 指定的信号编号来设置该信号的处理函数 while(pid1=fork()=-1);/程序等待成功创立子进程事件的发生 if(pid10)/当前进程为父进程 while(pid2=fork()=-1);if(pid20)/当前进程为父进程,父进程发出两个中断信号 Kill 子进程 flag=1;sleep(5);kill(pid1,16);/将 16 指定的信号传给进程 ID 为 pid1 的进程 kill(pid2,17);/将 17 指定的信号传给进程 ID
9、为 pid2 的进程 wait(0);/暂时停顿目前进程的执行,直到有信号来到或子进程完毕 wait(0);printf(n parent is killedn);e*it(E*IT_SUCCESS);else /当前进程为子进程,则发送子进程 kill 信号,杀死该子进程 2 flag=1;signal(17,stop);printf(n child2 is killed by parentn);e*it(E*IT_SUCCESS);-else /当前进程为子进程,则发送子进程 kill 信号,杀死该子进程 1 flag=1;signal(16,stop);printf(n child1 i
10、s killed by parentn);e*it(E*IT_SUCCESS);void stop()flag=0;程序运行结果:每个进程父进程,子进程都有一个 flag,起状态标志作用,flag=1 时,表示进程在运行,flag=0,表示进程完毕。5编写程序,要求父进程创立一个子进程,使父进程和个子进程各自在屏幕上输出一些信息,但父进程的信息总在子进程的信息之后出现。程序源代码:程序运行结果:6编写程序,要求父进程创立一个子进程,子进程执行 shell 命令 find/-name hda*的功能,子进程完毕时由父进程打印子进程完毕的信息。执行中父进程改变子进程的优先级。程序源代码:程序运行结
11、果:7/*编写程序,要求父进程创立一个子进程,子进程对一个 50*50 的字符数组赋值,由父进程改变子进程的优先级,观察不同优先级进程使用 CPU 的时间。*/8查阅 Linu*系统中 structtask_struct 的定义,说明每项成员的作用。注:search in/usr/src/linu*-2.6/include/linu*/sched.h 广义上,所有的进程信息被放在一个叫做进程控制块的数据构造中,可以理解为进程属性的集合。每个进程在核中都有一个进程控制块(PCB)来维护进程相关的信息,Linu*核的进程控制块是 task_struct 构造体。task_struct 是 Linu
12、*核的一种数据构造,它会被装载到RAM 里并且包含着进程的信息。每个进程都把它的信息放在 task_struct 这个数据构造里,task_struct 包含了这些容:1标示符:描述本进程的唯一标示符,用来区别其他进程。-2状态:任务状态,退出代码,退出信号等。3优先级:相对于其他进程的优先级。4程序计数器:程序中即将被执行的下一条指令的地址。5存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的存块的指针。6上下文数据:进程执行时处理器的存放器中的数据。7IO 状态信息:包括显示的 I/O 请求,分配给进程的 IO 设备和被进程使用的文件列表。8记账信息:可能包括处理器时间总和,使
13、用的时钟数总和,时间限制,记账号。保存进程信息的数据构造叫做 task_struct,并且可以在 include/linu*/sched.h 里找到它。所有运行在系统里的进程都以 task_struct 链表的形式存在核里。进程的信息可以通过/proc 系统文件夹查看。task_struct 一些字段的介绍:1.调度数据成员(1)volatile long states;表示进程的当前状态(2)unsigned long flags;进程标志(3)long priority;进程优先级。优先级可通过系统调用sys_setpriorty 改变。(4)unsigned long rt_priori
14、ty;rt_priority 给出实时进程的优先级,rt_priority+1000 给出进程每次获取 CPU 后可使用的时间(同样按 jiffies 计)。实时进程的优先级可通过系统调用 sys_sched_setscheduler()改变(见 kernel/sched.c)。(5)long counter;在轮转法调度时表示进程当前还可运行多久。在进程开场运行是被赋为 priority 的值,以后每隔一个 tick(时钟中断)递减 1,减到 0 时引起新一轮调度。重新调度将从run_queue队列选出counter值最大的就绪进程并给予CPU使用权,因此 counter 起到了进程的动态优
15、先级的作用(priority 则是静态优先级)。(6)unsigned long policy;该 进 程 的 进 程 调 度 策 略,可 以 通 过 系 统 调 用sys_sched_setscheduler()更改(见 kernel/sched.c)。调度策略有:SCHED_OTHER0 非实时进程,基于优先权的轮转法(round robin)。SCHED_FIFO1 实时进程,用先进先出算法。SCHED_RR 2 实时进程,用基于优先权的轮转法。2.信号处理(1)unsigned long signal;进程接收到的信号。每位表示一种信号,共 32 种。置位有效。(2)unsigned
16、long blocked;进 程 所 能 承 受 信 号 的 位 掩 码。置 位 表 示 屏 蔽,复 位 表 示 不 屏 蔽。(3)structsignal_struct*sig;因为 signal 和 blocked 都是 32 位的变量,Linu*最多只能承受32 种信号。对每种信号,各进程可以由 PCB 的 sig 属性选择使用自定义的处理函数,或是系统的缺省处理函数。指派各种信息处理函数的构造定义在 include/linu*/sched.h 中。对 信 号 的 检 查 安 排 在 系 统 调 用 完 毕 后,以 及 慢 速 型 中 断 效 劳 程 序 完 毕 后(IRQ#_inter
17、rupt()。3.进程队列指针(1)structtask_struct*ne*t_task,*prev_task;所有进程(以 PCB 的形式)组成一个双向链表。ne*t_task 和就是链表的前后指针。链表的头和尾都是 init_task(即 0 号进程)。(2)structtask_struct*ne*t_run,*prev_run;由正在运行或是可以运行的,其进程状态均为 TASK_RUNNING 的进程所组成的一个双向循环链表,即 run_queue 就绪队列。该链表的前后向指针用 ne*t_run 和 prev_run,链表的头和尾都 是init_task(即0号 进 程)。(3)s
18、tructtask_struct*p_opptr,*p_pptr;和structtask_struct*p_cptr,*p_ysptr,*p_osptr;以上分别是指向原始父进程(original parent)、父进程(parent)、子进程(youngest child)及新老兄弟进程(younger sibling,older sibling)的指针。4.进程标识(1)unsigned short uid,gid;uid 和 gid 是运行进程的用户标识和用户组标识。(2)int groupsNGROUPS;与多数现代UNI*操作系统一样,Linu*允许进程同时拥有一组用户组号。在进程文
19、件时,这些组号可用于合法性检查。(3)unsigned short euid,egid;euid和egid又称为有效的uid和gid。出于系统平安的权限的考虑,运行程序时要检查euid和 egid 的合法性。通常,uid 等于 euid,gid 等于 egid。有时候,系统会赋予一般用户暂-时拥有 root 的 uid 和 gid(作为用户进程的 euid 和 egid),以便于进展运作。(4)unsigned short fsuid,fsgid;fsuid 和 fsgid 称为文件系统的 uid 和 gid,用于文件系统操作时的合法性检查,是 Linu*独特的标识类型。它们一般分别和 eui
20、d 和 egid 一致,但在 NFS 文件系统中 NFS 效劳器需要作为一个特殊的进程文件,这时只修改客户进程的 fsuid 和 fsgid。(5)unsigned short suid,sgid;suid 和 sgid 是根据 POSI*标准引入的,在系统调用改变 uid 和 gid 时,用于保存真正的uid 和 gid。(6)intpid,pgrp,session;进程标识号、进程的组织号及 session 标识号,相关系统调用(见程序 kernel/sys.c)有 sys_setpgid、sys_getpgid、sys_setpgrp、sys_getpgrp、sys_getsid 及 s
21、ys_setsid 几种。(7)int leader;是否是 session 的主管,布尔量。5.时间数据成员(1)unsigned long timeout;用于软件定时,指出进程间隔多久被重新唤醒。采用 tick 为单位。(2)unsigned long it_real_value,it_real_iner;用于itimer(interval timer)软件定时。采用 jiffies 为单位,每个 tick 使 it_real_value 减到 0时向进程发信号 SIGALRM,并重新置初值。初值由 it_real_incr 保存。具体代码见kernel/itimer.c 中的函数 it
22、_real_fn()。(3)structtimer_listreal_timer;一种定时器构造(Linu*共 有 两 种 定 时 器 构 造,另 一 种 称 作old_timer)。数 据 构 造 的 定 义 在include/linu*/timer.h中,相关操作函数见kernel/sched.c中add_timer()和del_timer()等。(4)unsigned long it_virt_value,it_virt_incr;关于进程用户态执行时间的 itimer 软件定时。采用 jiffies 为单位。进程在用户态运行时,每个 tick 使 it_virt_value 减 1,减
23、到0 时向进程发信号 SIGVTALRM,并重新置初值。初值由 it_virt_incr 保存。具体代码见kernel/sched.c 中的函数 do_it_virt()。(5)unsigned long it_prof_value,it_prof_incr;同样是 itimer 软件定时。采用 jiffies 为单位。不管进程在用户态或核态运行,每个 tick 使it_prof_value 减 1,减到 0 时向进程发信号 SIGPROF,并重新置初值。初值由 it_prof_incr保存。具体代码见 kernel/sched.c 中的函数 do_it_prof。(6)long utime,
24、stime,cutime,cstime,start_time;以上分别为进程在用户态的运行时间、进程在核态的运行时间、所有层次子进程在用户态的运行时间总和、所有层次子进程在核心态的运行时间总和,以及创立该进程的时间。6.信号量数据成员(1)structsem_undo*semundo;进程每操作一次信号量,都生成一个对此次操作的 undo 操作,它由 sem_undo 构造描述。这些属于同一进程的 undo 操作组成的链表就由 semundo 属性指示。当进程异常终止时,系统会调用 undo操作。sem_undo 的成员 semadj 指向一个数据数组,表示各次 undo 的量。构造定义在in
25、clude/linu*/sem.h。(2)structsem_queue*semsleeping;每一信号量集合对应一个sem_queue 等待队列(见 include/linu*/sem.h)。进程因操作该信号量集合而阻塞时,它被挂到semsleeping指示的关于该信号量集合的sem_queue队列。反过来,semsleeping。sleeper 指向该进程的 PCB。7.进程上下文环境(1)structdesc_struct*ldt;进程关于 CPU段式存储管理的局部描述符表的指针,用于仿真 WINE Windows 的程序。其他情况下取值NULL,进 程 的ldt就 是arch/i38
26、6/traps.c定 义 的default_ldt。(2)structthread_structtss;任务状态段,其容与 INTEL CPU 的 TSS 对应,如各种通用存放器.CPU 调度时,当前运行进程的 TSS 保存到 PCB 的 tss,新选中进程的 tss 容复制到 CPU的TSS。构造定义在include/linu*/tasks.h中。(3)unsigned long saved_kernel_stack;为 MS-DOS 的仿真程序(或叫系统调用 vm86)保存的堆栈指针。(4)unsigned long kernel_stack_page;在核态运行时,每个进程都有一个核堆栈
27、,其基地址就保存在kernel_stack_page 中。8.文件系统数据成员(1)structfs_struct*fs;fs 保存了进程本身与 VFS 的关系消息,其中 root 指向根目录结点,pwd 指向当前目录结点,umask 给出新建文件的模式(可由系统调用 umask 更改),count 是 Linu*保存的属性,-如下页图所示。构造定义在 include/linu*/sched.h 中。(2)structfiles_struct*files;files 包含了进程当前所翻开的文件(struct file*fdNR_OPEN)。在 Linu*中,一个进程最多只能同时翻开 NR_OP
28、EN 个文件。而且,前三项分别预先设置为标准输入、标准输出和出错消息输出文件。(3)intlink_count;文件链(link)的数目。Array.存数据成员(1)structmm_struct*mm;在 linu*中,采用按需分页的策略解决进程的存需求。task_struct的数据成员 mm 指向关于存储管理的 mm_struct 构造。其中包含了一个虚存队列 mmap,指向由假设干 vm_area_struct 描述的虚存块。同时,为了加快速度,mm 中的 mmap_avl维护了一个 AVL 树。在树中,所有的 vm_area_struct 虚存块均由左指针指向相邻的低虚存块,右指针指向相邻的高虚存块。构造定义在 include/linu*/sched.h 中。