Unix进程管理1.进程的基本概念2.进程结构3.进程映像4.进程状态5.进程调度6.进程控制7.进程通信(IPC,INTER-PROCESSCOMMUNICATION)1.进程的概念•程序在其上下文中的一次执行.•除0#和1#进程外,由fork创建的实体的集合*讲授以UNIXSystemv为例,为理解方便,有些改动。2.UNIX进程结构shelllspwdprogram1program2program3sort1#Loginshellprog1ls$ls|sort3.UNIX进程上下文•进程上下文:指进程的用户地址空间内容、寄存器内容及与进程相关的核心数据结构;包括三部分上下文:用户级、寄存器级、系统级•用户级上下文:正文段即代码(text);数据段(data);栈段(userstack):用户态执行时的过程调用;共享存储区(sharedmemory)–把地址空间的段称为区(region):进程区表和系统区表(前者索引指向后者)•系统上下文:–proc结构:总在内存,内容包括阻塞原因;–user结构:可以调出到外存,进程处于执行状态时才用得着,各种资源表格;–进程区表:从虚拟地址到物理地址的映射;–核心栈:核心态执行时的过程调用的栈结构;进程PCB(proc+user)•Proc:structproc{}proc[N];p_stat;进程状态如:SRUN,SSLEEP,SZOMB...p_flag;每位代表一个含义,如:SLOAD,…p_pri;优先级,如:-100-127p_cpu;p_nice;计算进程动态优先数p_sig;接受软中断信号p_uid;进程的用户标识p_pid;进程标识符p_ppid;父进程的标识符p_time;进程在内存或外存的驻留时间p_addr;user区的地址(现代:p_ubptb,p_regin)p_size;user区的大小p_ttyp;进程相关终端p_textp;指向共享正文段表p_wchan;进程等待原因进程PCB(proc+user)•User:structuser{…};主要包括:u_procp;(指向proc)u_tsize;u_dsize;u_ssize;(正文段,数据段,用户栈大小)u_rsav[2];u_qsav[2];u_ssav[2];(保留进程现场)u_ttyp;(终端)u_cdir;(当前目录)u_signal[NSIG];(软中断处理程序)u_uid;u_gid;u_ruid;u_rgid;(用户,组标识)u_arg[6];(传递系统调用参数)u_ofile[NFILE];(用户打开文件表)u_base;u_count;u_offset;(文件系统调用)u_utime;u_stime;u_cutime;u_cstime;(CPU时间)系统共享正文段表text•Structtext{….}text[M];x_caddr;(内存始地址)x_daddr;(磁盘始地址)x_size;(正文段大小)x_count;(共享进程计数)用户栈数据段核心栈user正文段proc[N]text[]p_addru_procpp_textpx_caddr核心区用户区进程上下文之间的联系4.进程状态°进程有9个状态,由p_stat和p_flag及处理机状态字决定:创建SIDL核心态运行SRUN用户态运行SRUN内存就绪SRUN&SLOAD外存就绪SRUN&!SLOAD内存睡眠SSLEEP&SLOAD(SWAITorSSTOP)外存睡眠SSLEEP&!SLOAD(SWAITorSSTOP)可抢先SRUN僵死SZOMB123456789进程状态(续)NotEnoughMemoryKernalRunningReadytoRun,SwappedZombieReadytoRun,inMemoryAsleepinMemoryRescheduleProcessSleepWakeupExitSleep,SwappedSwapOutCreatedWakeupSwapInEnoughMemoryForkSwapOutUserRunningPreemptedReturnSystemCall,InterruptInterrupt,InterruptReturnPreemptReturntoUser注意:状态“被抢先”与“内存就绪”的地位相同,要等到下一次进程调度时,才能回到“用户态执行”。1234567895.进程调度•Swtch:采用动态优先数法p_pri=p_cpu/2+PUSER+p_nice+NZERO2520系统进程优先级高:SCHED=-100,打印机=10,I/O缓存=-50.计算方法:1.每个时钟周期,当前进程p_cpu+1;2.每秒钟时钟中断时,全部进程的p_cpu/2,计算所有进程的p_pri,若当前进程不是最小,设runrun=13.进程从中断或陷入返回时,计算当前进程的p_pri基本上每个进程占用CPU时间不会超过一秒进程调度(续)•调度时机1.进程结束。2.进程睡眠SSLEEPorSWAIT。3.进程暂停SSTOP。4.当前进程需扩充内存,内存没空,被交换到外存。5.等待共享段调入内存6.进程从核心态返回时,runrun=1.唤醒进程时可能设runrun.计算进程p_pri时可能设runrun当前进程状态如何变换?6.进程控制•fork:创建子进程•wait:父进程等待子进程结束•exit:进程结束•exec:进程更换正文段fork---创建进程fork()={0---子进程返回子进程pid---父进程返回1。调用格式2。使用方法main(){….while((x=fork())==-1);if(x==0){子进程语句}else{父进程语句}父、子都执行语句;}例:main(){intx;while((x=fork())==-1);if(x==0)printf(“a”);elseprintf(“b”);printf(“c”);}abcc?bcac?abcc?acbc?cabc?结果?fork()在proc数组中找一个空表项找到否?p_pid=系统赋标识号码p_stat=SRUN;p_ppid=当前进程pid;复制父进程的p_textp,p_sizep_uid,p_ttyp,p_nice...x_count++;f_count++内存有空?为子进程申请空间;复制user,数据段;u_procp指向proc;u_utime=0;u_stime=0;栈指针--u_rsav[2];子进程返回0;父进程返回子进程pid;yy在磁盘复制n父:子pid子:0用户栈数据段核心栈user正文段proc[N]text[]p_addru_procpp_textpx_caddr核心区用户区父进程创建子进程用户栈数据段核心栈user子u_procpp_addrp_textp父fork例main(){intchild,i=2;if((child=fork())==-1){printf(forkerror.);exit();}if(child==0){i=i+3;printf(“i=%d\n”,i);}i=i+5;printf(“i=%d\n”,i);}1.forkerror2.i=5i=10i=73.i=7i=5i=104.i=5i=7i=10插入else呢?父子1子2main(){if(fork()==0){子1的代码段}else{if(fork()==0){子2的代码段}else{父代码段}}}父子1子2main(){if(fork()==0){子1的代码段;if(fork()==0){子2的代码段}else{子1的代码段}}else{父代码段}}去掉这个else谁执行这一段?exec-执行文件•更换进程执行代码,更换正文段,数据段•调用格式:exec(文件名,参数表,环境变量表)•例:execlp(“max”,15,18,10,0);execvp(“max”,argp)main(){if(fork()==0){printf(“a”);execlp(“file1”,0);printf(“b”);}printf(“c”);}file1:main(){printf(“d”);}acd?cad?adc?abdc?adbcc?exec(文件名,参数表)参数复制到系统空间取文件i节点,验证文件释放老分区按文件头指定的文件大小,分配新分区,装入新分区Exec参数复制到新用户栈初始化各分区使能返回用户态释放文件i节点头正文段数据段工作区数据段核心栈user数据段核心栈userproctext正文段可执行文件wait--等待子进程结束exit---终止进程•使用方法:main(){intn;….if(fork()==0){printf(“a”);exit(0);}wait(&n);printf(“b”);}printf(“c”);exit(intstatus)关闭打开文件表工作目录。u_ofile,u_cdir释放正文段x_count--;...status--useruser--磁盘p_addr--盘user释放user,所有栈,数据段p_stat=SZOMB将所有子进程的父进程改为1号进程(p_ppid)wakeup(p_ppid);swtchwait(int*stat)有子进程结束?从盘上取出子进程user(father)(sun)u_cutime+=u_utime;u_cstime+=u_stime;u_cutime+=u_cutime;u_cstime+=u_cstimeuser中的status--stat释放子进程的proc返回子进程的pidsleep(u_procp,PWAIT)shell程序……while(true){printf(“$”);scanf(“%s”,&command);检查命令的语法;if(fork()==0){…..execlp(command,参数表,0);}if(command后缀!=‘&’)wait(…);…..}上机作业•getpid()---获取进程的pid作业一:每个进程都执行自己独立的程序,打印自己的pid,父进程打印两个子进程的pid;父子1子2作业二:父子1子2同作业一要求。子2与父代码同作业三:写一个命令处理程序,能处理max(m,n),min(m,n)average(m,n,l)这几个命令(前后台都可以)。实例:UNIX_wait演示子进程与父进程的关系和fork、exec、wait的使用;程序main.c功能是进行10次循环,创建2个子进程。循环到第3次时,等待子进程结束。#includesys/types.h#includeunistd.h#includestdio.h#includesys/wait.hpid_twait(int*stat_loc);voidperror(constchar*s);#includeerrno.hinterrno;intglobal;main(){intlocal,i;pid_tchild;if((child=fork())==-1){//创建失败printf(ForkError.\n);}if(child==0){//子进程printf(Nowitisinchildprocess.\n);if(execl(/home/xyong/work/ttt,ttt,NULL)==-1){//加载程序失败perror(Errorinchildprocess);}global=local+2;exit();}//父进程printf(Nowitisinparentprocess.\n);for(i=0;i10;i++){sleep(2);printf(Parent:%d\n,i);if(i==2){if((child=fork())==-1){//创建失败printf(ForkError.\n);}if(child==0){//子进程printf(Nowitisinchildprocess.\n);if(ex