兰州大学操作系统实验五详细答案.docx

上传人:b****4 文档编号:5591980 上传时间:2023-05-08 格式:DOCX 页数:27 大小:949.97KB
下载 相关 举报
兰州大学操作系统实验五详细答案.docx_第1页
第1页 / 共27页
兰州大学操作系统实验五详细答案.docx_第2页
第2页 / 共27页
兰州大学操作系统实验五详细答案.docx_第3页
第3页 / 共27页
兰州大学操作系统实验五详细答案.docx_第4页
第4页 / 共27页
兰州大学操作系统实验五详细答案.docx_第5页
第5页 / 共27页
兰州大学操作系统实验五详细答案.docx_第6页
第6页 / 共27页
兰州大学操作系统实验五详细答案.docx_第7页
第7页 / 共27页
兰州大学操作系统实验五详细答案.docx_第8页
第8页 / 共27页
兰州大学操作系统实验五详细答案.docx_第9页
第9页 / 共27页
兰州大学操作系统实验五详细答案.docx_第10页
第10页 / 共27页
兰州大学操作系统实验五详细答案.docx_第11页
第11页 / 共27页
兰州大学操作系统实验五详细答案.docx_第12页
第12页 / 共27页
兰州大学操作系统实验五详细答案.docx_第13页
第13页 / 共27页
兰州大学操作系统实验五详细答案.docx_第14页
第14页 / 共27页
兰州大学操作系统实验五详细答案.docx_第15页
第15页 / 共27页
兰州大学操作系统实验五详细答案.docx_第16页
第16页 / 共27页
兰州大学操作系统实验五详细答案.docx_第17页
第17页 / 共27页
兰州大学操作系统实验五详细答案.docx_第18页
第18页 / 共27页
兰州大学操作系统实验五详细答案.docx_第19页
第19页 / 共27页
兰州大学操作系统实验五详细答案.docx_第20页
第20页 / 共27页
亲,该文档总共27页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

兰州大学操作系统实验五详细答案.docx

《兰州大学操作系统实验五详细答案.docx》由会员分享,可在线阅读,更多相关《兰州大学操作系统实验五详细答案.docx(27页珍藏版)》请在冰点文库上搜索。

兰州大学操作系统实验五详细答案.docx

兰州大学操作系统实验五详细答案

实验五

实验名称:

进程管理

实验报告:

实验要求:

cat/etc/group(查看组信息)

1.编写一个程序,打印进程的如下信息:

进程标识符,父进程标识符,真实用户ID,有效用户ID,真实用户组ID,有效用户组ID。

并分析真实用户ID和有效用户ID的区别。

代码如下:

#include

#include

intmain(){

printf("***********\n");

printf("Thisistheprocess\n");

printf("pid=%d\n",getpid());

printf("ppid=%d\n",getppid());

printf("uid=%d\n",getuid());

printf("euid=%d\n",geteuid());

printf("gid=%d\n",getgid());

printf("egid=%d\n",getegid());

}

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

真实用户ID:

这个ID就是我们登陆unix系统时的身份ID。

有效用户ID:

定义了操作者的权限。

有效用户ID是进程的属性,决定了该进程对文件的访问权限.

2.阅读如下程序:

/*processusingtime*/

#include

#include

#include

#include

#include

voidtime_print(char*,clock_t);

intmain(void)

{

clock_tstart,end;

structtmst_start,t_end;

start=times(&t_start);

system(“grepthe/usr/doc/*/*>/dev/null2>/dev/null”);//>将信息放到该文件null中

end=times(&t_end);//012标准输入标准输出错误输出

time_print(“elapsed”,end-start);

puts(“parenttimes”);

time_print(“\tuserCPU”,t_end.tms_utime);

time_print(“\tsysCPU”,t_end.tms_stime);

//获得执行system()的子进程ID

puts(“childtimes”);

time_print(“\tuserCPU”,t_end.tms_cutime);

time_print(“\tsysCPU”,t_end.tms_cstime);

exit(EXIT_SUCCESS);

}

voidtime_print(char*str,clock_ttime)

{

longtps=sysconf(_SC_CLK_TCK);/*函数sysconf()的作用为将时钟滴答数转化为秒数,_SC_CLK_TCK为定义每秒钟有多少个滴答的宏*/

printf(“%s:

%6.2fsecs\n”,str,(float)time/tps);

}

编译并运行,分析进程执行过程的时间消耗(总共消耗的时间和CPU消耗的时间),并解释执行结果。

再编写一个计算密集型的程序替代grep,比较两次时间的花销。

注释程序主要语句。

因为该程序计算量很小,故消耗的时间比较少,均为0.00secs不奇怪。

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

3.阅读下列程序:

/*forkusage*/

#include

#include

#include

intmain(void)

{

pid_tchild;

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

perror(“fork”);

exit(EXIT_FAILURE);

}elseif(child==0){

puts(“inchild”);

printf(“\tchildpid=%d\n”,getpid());//取得目前进程的进程ID

printf(“\tchildppid=%d\n”,getppid());//取得目前进程的父进程ID

exit(EXIT_SUCCESS);

}else{

puts(“inparent”);

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

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

}

exit(EXIT_SUCCESS);

}

编译并多次运行,观察执行输出次序,说明次序相同(或不同)的原因;观察进程ID,分析进程ID的分配规律。

总结fork()的使用方法。

注释程序主要语句。

创建进程ID开始时一般随机分配,但若多次运行,或创建子进程时,会顺序分配内存。

此外,当父进程结束时,子进程尚未结束,则子进程的父进程ID变为1,即init

fork()的使用方法:

fork()会产生一个新的子进程,其子进程会复制父进程的数据与堆栈空间,如果fork()成功则在父进程会返回新建立的子进程代码(PID),而在新建立的子进程中则返回0。

如果fork失败则直接返回-1,失败原因存于errno中。

在父进程中用fork()创建子进程,通过返回值if语句判断来进行父子进程代码执行。

4.阅读下列程序:

/*usageofkill,signal,wait*/

#include

#include

#include

#include

intflag;

voidstop();//该函数是自定义的一个single()触发的自定义函数

intmain(void)

{

intpid1,pid2;//定义了两个进程号参数

signal(3,stop);//signal()触发软中断

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

if(pid1>0){

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

if(pid2>0){//当前进程为父进程,父进程发出两个中断信号Kill子进程

flag=1;

sleep(5);

kill(pid1,16);

kill(pid2,17);

wait(0);//等待子进程死信号

wait(0);

printf(“\nparentiskilled\n”);//接收到子进程死信号后,杀死父进程

exit(EXIT_SUCCESS);

}else{//当前进程为子进程,则发送子进程Kill信号,杀死该子进程2

flag=1;

signal(17,stop);

printf(“\nchild2iskilledbyparent\n”);

exit(EXIT_SUCCESS);

}

}else{//当前进程为子进程,则发送子进程Kill信号,杀死该子进程1

flag=1;

signal(16,stop);

printf(“\nchild1iskilledbyparent\n”);

exit(EXIT_SUCCESS);

}

}

voidstop(){//自定义函数,供signal()调用

flag=0;

}

编译并运行,等待或者按^C,分别观察执行结果并分析,注释程序主要语句。

flag有什么作用?

通过实验说明。

每个进程(父进程,子进程)都有一个flag,起状态标志作用,flag=1时,表示进程在运行,flag=0,表示进程结束。

5.编写程序,要求父进程创建一个子进程,使父进程和子进程各自在屏幕上输出一些信息,但父进程的信息总在子进程的信息之后出现。

(分别通过一个程序和两个程序实现)

代码如下:

Ptest.c---------------一个程序实现方案(fork())

#include

#include

#include

main()

{

intp,i;

while((p=fork())==-1);//创建子进程直至成功

if(p>0)

{

wait(0);

printf("***\n");

printf("Theparentprocess!

\n");

printf("***\n");

exit(0);

}

else{

printf("***\n");

printf("Thechildprocess!

\n");

printf("***\n");

sleep(3);

exit(0);

}

}

/////////////////////////////////////////////////////////////////////////////////////

Ptest2.c------------------两个程序实现方案(execl())

#include

#include

#include

intmain(intargc,char*argv[])

{

intp,i;

while((p=fork())==-1);//创建子进程直至成功

if(p>0)

{

wait(0);

printf("***\n");

printf("Theparentprocess!

\n");

printf("***\n");

exit(0);

}

else{

printf("***\n");

printf("Thechildprocess!

\n");

execl("/home/xingkong/ptest22",argv[1],(char*)0);

printf("***\n");

sleep(3);

exit(0);

}

}

ptest22.c

#include

#include

intmain(intargc,char*argv[])

{

inti;

printf("*****\nThisistwoprocess\n*****\n");

for(i=0;i

{

printf("parameter%dis:

%s\n",i,argv[i]);

}

return0;

}

6.编写程序,要求父进程创建一个子进程,子进程执行shell命令find/-namehda*的功能,子进程结束时由父进程打印子进程结束的信息。

执行中父进程改变子进程的优先级。

代码如下:

#include

#include

#include

#include

#include

#include

#include

main(){

pid_tpid;

intstatus;

pid=fork();

if(pid>0){

//在父进程中设置子进程优先级

setpriority(PRIO_PROCESS,pid,15);

//输出修改后的子进程的优先级

printf("thepriorityofsonprocessis%d\n",getpriority(PRIO_PROCESS,pid));

}

//子进程执行代码

else{

execlp("find","find","/","-name","hda*",(char*)0);

exit(127);

}

/*使用waitpid()阻塞等待子进程结束,防止父进程过早的退出。

子进程终止后,waitpid()返回

返回后,可以打印子进程已经终止的信息。

*/

if((pid=waitpid(pid,&status,0))==-1){

fprintf(stderr,"[parent]waitpiderror:

%s\n",strerror(errno));

exit(-1);

}

fprintf(stdout,"child[%d]terminated\n",pid);

exit(0);

}

7.编写程序,要求父进程创建一个子进程,子进程对一个50*50的字符数组赋值,由父进程改变子进程的优先级,观察不同优先级进程使用CPU的时间。

代码如下:

#include

#include

#include

#include

#include

#include

voidtime_print(char*str,clock_ttime){

longtps=sysconf(_SC_CLK_TCK);

printf("%s:

%6.2fsecs",str,(float)time/tps);

}

main(){

pid_tpid;

clock_tstart,end;

structtmst_start,t_end;

pid=fork();

start=times(&t_start);

if(pid>0){

//在父进程中设置子进程优先级

setpriority(PRIO_PROCESS,pid,20);

//输出修改后的子进程的优先级

printf("thepriorityofsonprocessis%d",getpriority(PRIO_PROCESS,pid));

}

//子进程执行代码

else{

inti,j,shu[50][50];

for(i=0;i<50;i++)

for(j=0;j<50;j++)

shu[i][j]=i+j;

system("grepthe/usr/*/*/*>/dev/null2>/dev/null");

}

end=times(&t_end);

time_print("\nelapsed",end-start);

printf("\nparenttime");

time_print("\tuserCPU",t_end.tms_utime);

time_print("\tsysCPU",t_end.tms_stime);

printf("\nchildtime");

time_print("\tuserCPU",t_end.tms_cutime);

time_print("\tsysCPU",t_end.tms_cstime);

printf("\n");

exit(0);

}

8.编写一个程序,模拟实现一个简单的进程管理子系统,它由进程建立模块、进程撤销模块、进程控制表组成。

该子系统通过循环显示“pleaseinputnewcommand”接收新进程,根据用户键入内容(命令)启动新进程,然后不等待新进程结束就显示“pleaseinputnewcommand”接收新进程。

建立和撤销进程时修改进程控制表。

9.查阅Linux系统中structtask_struct(有很多结构体类型的指针,至少写出三级指针)的定义,说明每项成员的作用。

(熟记该嵌套结构体)

StructTask_struct{

*--------------------------------------à新的结构体定义{

*---------------------------------------à新的结构体定义

}

}

一级指针

每一个进程都有一个进程描述符,具体是task_struct结构体存储相关的信息.

structtask_struct{

//这个是进程的运行时状态,-1代表不可运行,0代表可运行,>0代表已停止。

volatilelongstate;

/*

flags是进程当前的状态标志,具体的如:

0x00000002表示进程正在被创建;

0x00000004表示进程正准备退出;

0x00000040表示此进程被fork出,但是并没有执行exec;

0x00000400表示此进程由于其他进程发送相关信号而被杀死。

*/

unsignedintflags;

//表示此进程的运行优先级

unsignedintrt_priority;

//list_head结构体

structlist_headtasks;

//mm_struct结构体,该结构体记录了进程内存使用的相关情况

structmm_struct*mm;

/*接下来是进程的一些状态参数*/

intexit_state;

intexit_code,exit_signal;

//这个是进程号

pid_tpid;

//这个是进程组号

pid_ttgid;

//real_parent是该进程的“亲生父亲”,不管其是否被“寄养”。

structtask_struct*real_parent;

//parent是该进程现在的父进程,有可能是“继父”

structtask_struct*parent;

/*这里children指的是该进程孩子的链表,可以得到所有孩子的进程描述符,但是需使用list_for_each和list_entry,list_entry其实直接使用了container_of,详情请参考*/

structlist_headchildren;

//同理,sibling该进程兄弟的链表,也就是其父亲的所有孩子的链表。

用法与children相似。

structlist_headsibling;

/*这个是主线程的进程描述符,也许你会奇怪,为什么线程用进程描述符表示,因为linux并没有单独实现线程的相关结构体,只是用一个进程来代替线程,然后对其做一些特殊的处理。

*/

structtask_struct*group_leader;

 

//这个是该进程所有线程的链表。

structlist_headthread_group;

//顾名思义,这个是该进程使用cpu时间的信息,utime是在用户态下执行的时间,stime是在内核态下执行的时间。

cputime_tutime,stime;

//下面的是启动的时间,只是时间基准不一样。

structtimespecstart_time;

structtimespecreal_start_time;

//comm是保存该进程名字的字符数组,长度最长为15,因为TASK_COMM_LEN为16。

charcomm[TASK_COMM_LEN];

/*文件系统信息计数*/

intlink_count,total_link_count;

/*该进程在特定CPU下的状态*/

structthread_structthread;

/*文件系统相关信息结构体*/

structfs_struct*fs;

/*打开的文件相关信息结构体*/

structfiles_struct*files;

/*信号相关信息的句柄*/

structsignal_struct*signal;

structsighand_struct*sighand;

/*这些是松弛时间值,用来规定select()和poll()的超时时间,单位是纳秒nanoseconds*/

unsignedlongtimer_slack_ns;

unsignedlongdefault_timer_slack_ns;

};

 

二级结构体及对应的三级结构体(2.代表二级的,3.代表三级的)

2.structmm_struct{//该结构体记录了进程内存使用的相关情况

intcount;

pgd_t*pgd;//为指向进程页目录表的指针。

unsignedlongcontext;//是进程上下文的地址

//分别为代码段、数据段的首地址和终止地址。

unsignedlongstart_code,end_code,start_data,end_data;

//start_stack是进程堆栈的首地址

unsignedlongstart_brk,brk,start_stack,start_mmap;

//分别为参数区、环境变量区的首地址和终止地址

unsignedlongarg_start,arg_end,env_start,env_end;

unsignedlongrss,total_vm,locked_vm;

unsignedlongdef_flags;

structvm_area_struct*mmap;

structvm_area_struct*mmap_avl;

structsemaphoremmap_sem;

};

3.structvm_area_struct{

      structmm_struct*vm_mm;//指向进程的mm_struct结构体

//虚存空间的首地址和末地址后第一个字节的地址

      unsignedlongvm_start;

      unsignedlongvm_end;

//通过vm_next指针指向下一个vm_area_struct结构

      structvm_area_struct*vm_next;

//虚存区域的页面的保护特性

      pgprot_tvm_page_prot;

      unsignedlongvm_flags;

//vm_flags指出了虚存区域的操作特性:

//VM_READ虚存区域允许读取

//VM_WRITE虚存区域允许写入

//VM_EXEC虚存区域允许执行

//VM_SHARED虚存区域允许多个进程共享

//VM_GROWSDOWN虚存区

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2