兰州大学操作系统实验五详细答案.docx
- 文档编号:11149650
- 上传时间:2023-02-25
- 格式:DOCX
- 页数:27
- 大小:949.97KB
兰州大学操作系统实验五详细答案.docx
《兰州大学操作系统实验五详细答案.docx》由会员分享,可在线阅读,更多相关《兰州大学操作系统实验五详细答案.docx(27页珍藏版)》请在冰豆网上搜索。
兰州大学操作系统实验五详细答案
实验五
实验名称:
进程管理
实验报告:
实验要求:
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虚存区
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 兰州大学 操作系统 实验 详细 答案