操作系统实验报告实验四

  • 格式:docx
  • 大小:803.76 KB
  • 文档页数:15

下载文档原格式

  / 15
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验四:进程管理(二)

实验容:

1.编写一个程序,打印进程的如下信息:进程标识符,父进程标识符,真实用户ID,有效用户ID,真实用户组ID,有效用户组ID。并分析真实用户ID和有效用户ID的区别。

源代码及结果:

真实用户ID和有效用户ID的区别:

真实用户ID:这个ID就是我们登陆unix系统时的身份ID。

有效用户ID:定义了操作者的权限。有效用户ID是进程的属性,决定了该进程对文件的访问权限。

2.阅读如下程序,编译并运行,分析进程执行过程的时间消耗(总共消耗的时间和CPU 消耗的时间),并解释执行结果。再编写一个计算密集型的程序替代grep,比较两次时间的花销。注释程序主要语句。

/* process using time */

#include

#include

#include

#include

#include

void time_print(char *,clock_t);

int main(void){

//取得进程运行相关的时间

clock_t start,end;

struct tms t_start,t_end;

start = times(&t_start);

system(“grep the /usr/doc/*/* > /dev/null 2> /dev/null”);

/*command >/dev/null的作用是将是command命令的标准输出丢弃,而标准错误输出还是在屏幕上。一般来讲标准输出和标准错误输出都是屏幕,因此错误信息还是会在屏幕上输出。>/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);

time_print(“\tsys CPU”,t_end.tms_cstime);

exit(EXIT_SUCCESS);

}

void time_print(char *str, clock_t time)

{

long tps = sysconf(_SC_CLK_TCK);

/*函数sysconf()的作用为将时钟滴答数转化为秒数,_SC_CLK_TCK 为定义每秒钟

有多少个滴答的宏*/

printf(“%s: %6.2f secs\n”,str,(float)time/tps);

}

程序运行结果:

因为该程序计算量很小,故消耗的时间比较少,CPU消耗时间均为0.00secs不足为奇。而进程的执行时间等于用户CPU时间和系统CPU时间加从硬盘读取数据时间之和。

密集型的程序替代grep:

更改为计算密集型的之后就较容易观察出消耗时间的差异。

3.阅读下列程序,编译并多次运行,观察执行输出次序,说明次序相同(或不同)的原因;观察进程ID,分析进程ID的分配规律。总结fork()的使用方法。注释程序主要语句。

/* fork usage */

#include

#include

#include

int main(void)

{

pid_t child;

if((child=fork())==-1){

perror(“fork”);

exit(EXIT_FAILURE);

}else if(child==0){

puts(“in child”);

printf(“\tchild pid = %d\n”,getpid());

printf(“\tchild ppid = %d\n”,getppid());

exit(EXIT_SUCCESS);

}else{

puts(“in parent”);

prin tf(“\tparent pid = %d\n”,getpid());

printf(“\tparent ppid = %d\n”,getppid());

}

exit(EXIT_SUCCESS);

}

程序运行结果:

(?)创建进程ID开始时一般随机分配,但若多次运行,或创建子进程时,会顺序分配存。此外,当父进程结束时,子进程尚未结束,则子进程的父进程ID变为1。

fork()函数的实质是一个系统调用(和write函数类似),其作用是创建一个新的进程,当一个进程调用它,完成后就出现两个几乎一模一样的进程,其中由fork()创建的新进程被称为

子进程,而原来的进程称为父进程。子进程是父进程的一个拷贝,即子进程从父进程得到了数据段和堆栈的拷贝,这些需要分配新的存;而对于只读的代码段,通常使用共享存方式进行访问。

4.阅读下列程序,编译并运行,等待或者按^C,分别观察执行结果并分析,注释程序主要语句。flag有什么作用?通过实验说明。

/* usage of kill,signal,wait */

#include

#include

#include

#include

int flag;

void stop(); //自定义函数,使flag=0,供signal调用

int main(void){

int pid1,pid2;

signal(3,stop); // signal()依参数3指定的信号编号来设置该信号的处理函数

while((pid1=fork()) ==-1); //程序等待成功创建子进程事件的发生

if(pid1>0){

//当前进程为父进程

while((pid2=fork()) ==-1);

if(pid2>0){

//当前进程为父进程,父进程发出两个中断信号Kill子进程

flag=1;

sleep(5);

kill(pid1,16); //将16指定的信号传给进程ID为pid1 的进程

kill(pid2,17); //将17指定的信号传给进程ID为pid2 的进程

wait(0); //暂时停止目前进程的执行,直到有信号来到或子进程结束

wait(0);

printf(“\n parent is killed\n”);