第七章进程控制 控制进程上下文的系统调用包括三类: 1、与存储相关的 fork exec brk 2、与同步相关的 exit wait signal kill 3、与属性相关的 setpgrp setuid 1
第七章 进程控制 控制进程上下文的系统调用包括三类: 1、与存储相关的 fork exec brk 2、与同步相关的 exit wait signal kill 3、与属性相关的 setpgrp setuid 1
7.1创建进程fork pid fork() fok算法主要完成以下操作: 1、检查系统资源,为新进程在核心进程表proc表中分配一 个空表项。 2、为子进程分配一个唯一的进程标识数PD,确认用户的总 进程数没有超限。 3、拷贝父进程的上下文到子进程中,包括真正用户标识号 、有效用户标识号、进程组号、调度优先权等。初始化子进 程中的相关参数,如初始优先权数、初始CPU使用时间、计 时域等。调整文件的引用计数等。 4、增加与该进程相关的file表项和活动inode表项的引用计 数。 5、对父进程返回子进程的进程号;对子进程则返回0。 2
7.1 创建进程 fork pid = fork( ) fork算法主要完成以下操作: 1、检查系统资源,为新进程在核心进程表proc表中分配一 个空表项。 2、为子进程分配一个唯一的进程标识数PID,确认用户的总 进程数没有超限。 3、拷贝父进程的上下文到子进程中,包括真正用户标识号 、有效用户标识号、进程组号、调度优先权等。初始化子进 程中的相关参数,如初始优先权数、初始CPU使用时间、计 时域等。调整文件的引用计数等。 4、增加与该进程相关的file表项和活动inode表项的引用计 数。 5、对父进程返回子进程的进程号;对子进程则返回0。 2
算法fork 输入:无 输出:对父进程是子进程的PID 对子进程是0 f 检查可用的核心资源(如内外存空间、页表等); 取一个空闲的进程表项和唯一的PID号; 检查用户没有过多的运行进程; 将子进程的状态设为“创建”状态; 将父进程的进程表项中的数据拷贝到子进程的进程表项中; 当前目录的索引节点和改变的根目录的引用计数加一; 系统打开文件表中相关表项的引用计数加一; 在内存中作父进程上下文的拷贝(包括u区、正文、数据、堆栈); 3
算法 fork 输入:无 输出:对父进程是子进程的PID 对子进程是0 { 检查可用的核心资源(如内外存空间、页表等); 取一个空闲的进程表项和唯一的PID号; 检查用户没有过多的运行进程; 将子进程的状态设为“创建”状态; 将父进程的进程表项中的数据拷贝到子进程的进程表项中; 当前目录的索引节点和改变的根目录的引用计数加一; 系统打开文件表中相关表项的引用计数加一; 在内存中作父进程上下文的拷贝(包括u区、正文、数据、堆栈); 3
算法fork(续) 在子进程的系统级上下文中压入虚设的系统级上下文层 :虚设的上下文层中含有使子进程能够识别自己的数据, * 并使子进程被调度时从这里开始 *1 f(正在执行的进程是父进程) 将子进程的状态设置为“就绪”状态; return(子进程的PID);从系统态到用户态*/ ese体当前正在执行的进程是子进程*/ { 初始化u区的计时域; return(0);休从系统态返回到用户态*I 3 4
算法 fork (续) 在子进程的系统级上下文中压入虚设的系统级上下文层 /* 虚设的上下文层中含有使子进程能够识别自己的数据, * 并使子进程被调度时从这里开始 */ if (正在执行的进程是父进程) { 将子进程的状态设置为“就绪”状态; return(子进程的PID); /* 从系统态到用户态 */ } else /* 当前正在执行的进程是子进程 */ { 初始化u区的计时域; return(0); /* 从系统态返回到用户态 */ } } 4
实例1:双进程文件拷贝 main(int argc,*argv[] { 两个进程共享读指针和写指 fdrd open(argv[1],O_RDONLY); 针,但运行的结果并不能保证新 fdwt create(argv[2],0666); 文件中的内容与老文件中的完全 fork)片 *父子进程执行下面相同的代码*/ 相同,这取决于父子两个进程的 rdwrt(); 调度顺序。 exit(0); 一多进程环境下的数据一 } 致性问题。 rdwrt() { for(;; { if(read(fdrd,&c,1)!=1) return; write(fdwt,&c,1)月 } 5
main(int argc, *argv[ ]) { fdrd = open(argv[1], O_RDONLY); fdwt = create(argv[2], 0666); fork( ); /* 父子进程执行下面相同的代码 */ rdwrt( ); exit(0); } rdwrt( ) { for(; ;) { if(read(fdrd, &c, 1) != 1) return; write(fdwt, &c, 1); } } 实例1:双进程文件拷贝 两个进程共享读指针和写指 针,但运行的结果并不能保证新 文件中的内容与老文件中的完全 相同,这取决于父子两个进程的 调度顺序。 —— 多进程环境下的数据一 致性问题。 5
实例2:确保数据一致性的双进程数据传输 写 读 [1] to chil [0] 父进程输出 子进程输入 父进程 子进程 读 写 父进程输入 [0] to_par [1] 子进程输出 在本例中,父子进程分别把自己的标准输入和标准输出重新定向到to chilz和 to_par管道中了,无论这两个进程执行相应的系统调用的顺序如何,两个管 道中的数据顺序不会发生变化,因此两个进程最终的读写结果不会改变。6
实例2:确保数据一致性的双进程数据传输 to_chil to_par [1] 写 [0] 读 [0] 读 [1] 写 父进程 子进程 子进程输入 子进程输出 父进程输出 父进程输入 在本例中,父子进程分别把自己的标准输入和标准输出重新定向到to_chil和 to_par管道中了,无论这两个进程执行相应的系统调用的顺序如何,两个管 道中的数据顺序不会发生变化,因此两个进程最终的读写结果不会改变。 6
#include char string[]="hello,world"; main() { int count,i; int to_par[2],to_chil[2]; 体到父、子进程的管道*/ char buf[256]; pipe(to_par); pipe(to_chil); if (fork()==0) { 快子进程从此处开始运行* close(0); *关闭老的标准输入* dup(to_chil[O]); *把管道to chill的读指针复制到标准输入*/ close(1); :关闭老的标准输出*/ dup(to_par[1]); *把管道to par的写指针复制到标准输出*/ close(to_par[1]); *关闭不再需要的管道描述符*/ close(to_chil[0]); close(to_par[0]); close(to_chil[1]); for (; if((count=read(0,buf,sizeof(buf))==0) exit(); write(1,buf,count); 7
#include char string[ ] = “hello,world”; main( ) { int count, i; int to_par[2], to_chil[2]; /* 到父、子进程的管道 */ char buf[256]; pipe(to_par); pipe(to_chil); if (fork( ) == 0) { /* 子进程从此处开始运行 */ close(0); /* 关闭老的标准输入 */ dup(to_chil[0]); /* 把管道to_chil的读指针复制到标准输入 */ close(1); /* 关闭老的标准输出 */ dup(to_par[1]); /* 把管道to_par的写指针复制到标准输出 */ close(to_par[1]); /* 关闭不再需要的管道描述符 */ close(to_chil[0]); close(to_par[0]); close(to_chil[1]); for (; ;) { if((count=read(0, buf, sizeof(buf)) == 0) exit(); write(1, buf, count); } 7
体父进程从此处开始运行* close(1); *重新设置父进程的标准输入和输出*/ dup(to_chil[1]); close(0); dup(to_par[0]); close(to_chil[1]); close(to_par[0]); close(to_chil[0]); close(to_par[1]); for (i=0;i<15;i++) write(1,string,strlen(string);体每次向to_chil管道写11个字符*/ read(0,buf,sizeof(buf)); /*每次从to par管道读256个字符*/ } } 8
/* 父进程从此处开始运行 */ close(1); /* 重新设置父进程的标准输入和输出 */ dup(to_chil[1]); close(0); dup(to_par[0]); close(to_chil[1]); close(to_par[0]); close(to_chil[0]); close(to_par[1]); for (i=0; i<15; i++) { write(1, string, strlen(string)); /* 每次向to_chil管道写11个字符 */ read(0, buf, sizeof(buf)); /* 每次从to_par管道读256个字符 */ } } 8
7.2软中断信号 1、软中断信号的作用: 通知进程发生了异步事件需要处理。 2、软中断信号的发送: 进程之间相互发送; 进程之内给自己发送。 3、发送软中断信号的方法: kl系统调用 9
7.2 软中断信号 1、软中断信号的作用: 通知进程发生了异步事件需要处理。 2、软中断信号的发送: 进程之间相互发送; 进程之内给自己发送。 3、发送软中断信号的方法: kill 系统调用 9
4、软中断信号的分类: (1)、与进程终止相关的软中断信号 例如进程退出时 (2)、与进程例外事件相关的软中断信号 例如地址越界、写只读内存区 (3)、在系统调用期间遇到不可恢复的条件相关的软中断信号 例如执行exec而系统资源已用完 (4)、在系统调用时遇到的非预测错误条件产生的软中断信号 例如调用不存在的系统调用、向无读进程的管道写数据 (5)、由在用户态下运行的进程发出的软中断信号 例如用k川向自己或其他进程发出的软中断信号 (6)、与终端交互有关的软中断信号 终端上按的break键或delete键等 (7)、跟踪进程执行的软中断信号 10
4、软中断信号的分类: (1)、与进程终止相关的软中断信号 例如进程退出时 (2)、与进程例外事件相关的软中断信号 例如地址越界、写只读内存区 (3)、在系统调用期间遇到不可恢复的条件相关的软中断信号 例如执行exec而系统资源已用完 (4)、在系统调用时遇到的非预测错误条件产生的软中断信号 例如调用不存在的系统调用、向无读进程的管道写数据 (5)、由在用户态下运行的进程发出的软中断信号 例如用kill向自己或其他进程发出的软中断信号 (6)、与终端交互有关的软中断信号 终端上按的break键或delete键等 (7)、跟踪进程执行的软中断信号 10