当前位置:首页 > 2009操作系统实验指导书Vmware版 - 图文
实验3 进程并发与同步
一、实验目的
1、加深对进程概念的理解,区分进程并发执行与串行执行; 2、掌握进程并发执行的原理,理解进程并发执行的特点;
3、了解fork( )系统调用的返回值,掌握用fork()创建进程的方法;熟悉wait、exit等系统调用;
4、能利用相应的系统调用实现进程树与进程间的同步。
二、实验内容
1、编写一C语言程序,实现在程序运行时通过系统调用fork( )创建两个子进程,使父、子三进程并发执行,父亲进程执行时屏幕显示“I am father”,儿子进程执行时屏幕显示“I am son”,女儿进程执行时屏幕显示“I am daughter”。
要求多次连续反复运行这个程序,观察屏幕显示结果的顺序,直至出现不一样的情况为止。要求有运行结果截图与结果分析
2、连续4个fork()的进程家族树,family1-1.c程序清单如下: #include
fork(); fork(); fork(); fork();
printf(“A\\n”); }
请根据程序运行结果,画出进程家族树,并分析原因。
3、修改程序1,在父、子进程中分别使用wait、exit等系统调用“实现”其同步推进,父进程必须等待儿子进程与女儿进程结束,才可以输出消息。写出相应的同步控制,并分析运行结果。
4、创建一个子进程,并给它加载程序,其功能是调用键盘命令“ls -l”,已知该键盘命令的路径与文件名为:/bin/ls。父进程创建子进程,并加载./child2程序。写出相应的程序代码并分析程序运行结果。
三、系统调用
创建子进程系统调用:fork() 格式 int fork( ); =0 返回值 >0 =-1 创建成功,从子进程返回 创建成功,从父进程返回,其值为子进程的PID号 创建失败 子进程创建时操作系统的工作: ? 检查同时运行的进程数目,若超过系统设定值,则创建失败,返回-1; ? 为子进程分配进程控制块task_struct结构,并赋予唯一进程标识符pid; ? 子进程继承父进程打开的所有文件及资源,对父进程的当前目录和所有已打开系统文件表项中的引用记数加1; 4
? 为子进程创建进程映像: ? 创建子进程映像静态部分:复制父进程映像静态部分 ? 创建子进程映像动态部分:初始化task_struct结构 ? 结束创建,置子进程为内存就绪状态,插入就绪队列,作为一个独立的进程被系统调度。 ? 若调用进程(父进程)返回,则返回创建的子进程标识符pid值(此时返回值>0); ? 若子进程被调度执行,则将其U区计时字段初始化然后返回(此时返回值=0)。
进程睡眠系统调用:sleep() 格式 参数 功能 进程终止系统调用:exit(status) 格式 参数 void exit(int status); status是子进程向父进程发送的终止信息,父进程使用wait( )系统调用来接收这个信息 将进程置僵死状态 功能 释放其所占有的资源 向父进程发本进程死信号,并发送信息status给父进程,将自己及自己的子进程运行CPU的时间总和留待父进程使用wait( )收集 sleep(n); n表示延时的秒数 进程睡眠n秒 头文件 #include
父进程等待子进程终止系统调用:wait()与waitpid() 格式1 参数 返回值 pid_t wait([int *stat_addr,] 0); *stat_addr中存放exit()所发来终止信号stat的值。 >=0 =-1 表示有子进程终止,其值为终止子进程的pid号 表示无子进程终止 头文件 #include < sys/wait.h > #include < sys/types.h > 5
功能 父进程使用它等待任意一个子进程终止,如果在执行wait()之前已经有一个子进程结束了,则对其做善后处理,并返回子进程的pid号,如果没有则返回-1,该进程阻塞,插入等待子进程终止的队列,当有子进程终止时被唤醒。在&stat_addr中保留了子进程僵死时的终止信息(不是返回值)。 注意:一个wait()只能用来等待一个子进程终止,如果等待多个子进程终止则需要使用多个wait()。 pid_t waitpid (pid_t pid, int * stat_addr, int options ); pid=0 等待与父进程同组的子进程 等待给定pid号的子进程 pid=-1,options=0 等同于wait(),等待任意子进程 pid>0 等待指定pid的子进程终止 格式2 参数 功能 说明:1)若父进程仅仅只是等待任意一个子进程结束,而不需要取子进程发来的信号,则可以简单地使用wait(0)。 2)如果该进程没有创建自己的子进程就不能使用wait()或waitpid(),否则系统会返回一个出错信息。 3)如果要取子进程执行exit()后所发来的终止信号stat,可以使用*stat来取该变量中的值,而不能使用wait()的返回值,因为wait()的返回值是该终止子进程的pid号。 将指定的可执行文件加载到指定进程映像中,覆盖该进程中原有的程序 系统调用:execl()、execle()、execlp()、execv()、execve()与execvp() 功能 将一个指定的程序装入调用它的进程的映像中,用这个可执行文件的副本去覆盖该进程的程序空间,从而改变调用进程的执行代码,使调用进程执行新引入的可执行程序(二进制代码文件) 内核在响应这组系统调用后做以下工作: 1)根据给出的路径名找到指定的可执行文件,检查该文件是否可执行,用户是否具有执行权限(该文件必须是编译连接后的二进制代码)。 2)将该文件载入到调用它的进程映像中覆盖其原来的程序。 3)为该程序的执行设置参数数组和环境变量。 4)启动该进程进入新的程序入口点去执行。 此组函数执行时,如果加载成功则直接执行,没有返回;若加载不成功则返回-1。 格式1 参数 功能 execv(file, argv) char *file 指向文件全名(路径名/文件名)的指针 char *argv[n] 指向命令及参数的指针 1)执行参数指定的命令或文件。 2)用该命令或可执行文件的副本覆盖调用它的子进程的映像 表示错误返回 返回值 =-1 头文件 #include
和参数数组argv[],其中的环境值可以用NULL取代。如果不带参数使用execl(),则这一步可以不做。 3)创建子进程后,在子进程的分支中,如果不带参数使用execl(filepath,0),如果带参数则使用execv(filepath,argv)来实现用指定的程序filepath覆盖子进程映像中原有的程序。 7
共分享92篇相关文档