第一次学这章也是稀里糊涂2333333,现在来看,除了有部分不理解,大部分还是能看懂了。
- 异常:控制流中的突变,用来响应处理器状态中的某些变化
- 处理器中,状态被编码为不同的位和信号。
- 状态变化被称为事件,可能和当前指令的执行直接相关,如VM缺页、除以零;也可能没有关系,如系统定时器产生信号、或一个I/O请求完成。
- 处理器检测到事件发生时,会通过“异常表”(跳转表),进行一个间接过程调用(异常),到一个专门设计用来处理这类事件的操作系统子程序——异常处理程序。
- 处理程序将控制返回给当前指令Icurr(当时间发生时正在执行的指令)
- 处理程序将控制返回给Inext(如果没有发生异常将会执行的下一条指令)
- 处理程序终止被中断的程序
- 异常处理
- 异常号:
- 由处理器的设计者分配
- 被零除、缺页、存储器访问违例、断点以及算术溢出
- 由操作系统内核(操作系统常驻存储器的部分)的设计者分配
- 系统调用、来自外部I/O设备的信号
- 由处理器的设计者分配
- 异常表起始地址放在异常表基寄存器的特殊CPU寄存器里。
- 中断一般为硬件中断;剩下三种异常指令又叫做故障指令。
- 异常号:
-
-
- 中断/硬件中断
- 中断处理程序:硬件中断的异常处理程序。
- I/O设备,例如网络适配器、磁盘控制器和定时器芯片。
- 陷阱
- 有意的异常。syscall n
- 在用户程序和内核之间提供一个像过程一样的接口,叫做系统调用。
- 故障
- 错误情况
- 经典示例:缺页异常
- 终止
- 不可恢复的致命错误
- 典型的是一些硬件错误,比如DRAM or SRAM位被损坏时发生的奇偶错误。
- 中断/硬件中断
-
- 进程【他来了,带着n多的面试题来了】
-
- 上下文:存放在存储器中的程序代码和数据、用户栈、内核栈、通用目的寄存器、浮点寄存器、状态寄存器、程序计数器、环境变量、打开文件描述符,各种内核数据结构,比如页表、进程表、文件表(把下文8.2.4的内容杂糅在一起了,后期调整)
- 进程提给应用程序的关键抽象:独立逻辑控制流、私有地址空间
- 逻辑控制流
- 用调试器单步执行程序,会看到一系列的PC(程序计数器)的值,唯一对应于包含在程序的可执行目标文件中的指令或是包含在运行时动态链接到我们程序的共享对象中的指令。这个PC值的序列叫做逻辑控制流。
- 注意:操作系统进程上限由cpu核数决定。
- Windows
- 任务管理器
- Linux
- 查看指令
-
unix> cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l # 物理cpu数 unix> cat /proc/cpuinfo| grep "cpu cores"| uniq # cpu核数 unix> cat /proc/cpuinfo| grep "processor"|wc -l # 逻辑cpu
-
- /proc目录是虚拟文件系统,存储当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,可以通过更改其中某些文件来改变内核的运行状态。基于/proc文件系统如上所述的特殊性,其内的文件也常被称作虚拟文件,并具有一些独特的特点。例如,其中有些文件虽然使用查看命令查看时会返回大量信息,但文件本身的大小却会显示为0字节。此外,这些特殊文件中大多数文件的时间及日期属性通常为当前系统时间和日期,这跟它们随时会被刷新(存储于RAM中)有关。【注:来自网络,之后看操统如果有提及再更新】
- 查看指令
- 多个进程轮流使用CPU,执行它的流的一部分,然后被抢占(暂时挂起)。进程通信IPC机制:管道、套接口、共享存储器、信号量。并发和并行。进程轮换运行:多任务。进程执行它的控制流的一部分:时间片。多任务也叫时间分片。
- 用调试器单步执行程序,会看到一系列的PC(程序计数器)的值,唯一对应于包含在程序的可执行目标文件中的指令或是包含在运行时动态链接到我们程序的共享对象中的指令。这个PC值的序列叫做逻辑控制流。
- 私有地址空间:虚拟内存那章也会讲
- 用户模式vs内核模式
- 限制一个应用可以执行的指令以及它可以访问的地址空间范围:用某个控制寄存器中的一个方式位。
- 内核模式下,进程可以执行指令集中任何指令,访问系统中任何存储器位置。
- 用户模式中进程不允许执行特权指令,比如停止处理器、改变方式位的值或者发起一个I/O操作,不允许用户模式中的进程直接引用地址空间中内核区内的代码和数据。但是可以通过系统调用接口简介访问。
- 常见问题:怎么让操作系统从用户态到内核态?一般回答是中断、异常、系统调用。但是这个回答可能会让人有点迷惑,因为我们在下表中看到,中断是异常的一个类别。这个回答是将异常特例化为故障和终止两种情况(可能还有陷阱)。还有一个常见问题是“中断、陷阱、异常的区别?”这里的陷阱可以举个例子,比如DOS里的BIOS中断调用。
- 用户态->内核态:read读文件、创建新进程fork、加载新程序execve、终止当前进程exit
- 上下文切换
- 组成:看上文
- 调度:内核可以决定抢占当前进程,重新开始一个先前被抢占的进程。
- 保存当前进程上下文
- 恢复某个先前被抢占进程所保存的上下文
- 将控制传递给这个新恢复的进程
- 可以发生上下文切换
- 系统调用:比如read(切换到另一个进程,原进程等待);sleep
- 中断:【时间片轮转】(这是我第一次把我找实习面试期间背的东西和书上具体内容联系起来……)周期性定时器中断,内核判定当前进程运行了足够长时间然后切换。
- 逻辑控制流
- 系统调用和错误
- Linux下输入"man syscalss"得到完整系统调用列表。
- 系统级函数(标准C库):系统调用/它们相关的包装函数
- (良好编程习惯)Unix系统级函数遇到错误时,使用错误包装函数进行错误检查。
- 【进程控制】
-
- 【思考一个可能不是特别相关的问题】父进程同时有子进程和线程,那么子进程和线程是什么关系?答案是没有任何关系,想一想父子进程都共享啥内容。举例:Web服务器有很多服务器,有很多服务线程,此外又定时启动一个进程删除临时文件。
- 【进程状态说明】以下分类里把进程分为“运行”、“暂停挂起”、“终止”三种状态。三态模型:运行态(获得处理机)、就绪态(已分配到除CPU以外的所有必要资源)、阻塞态(等待事件发生,比如等待I/O完成、申请缓冲区不能满足、等待信号)。五态模型多了新建态和终止态。
-
回收子进程
-
回收:进程终止,内核并非立即把它从系统中清除,而是被保持在一种终止状态中,直到被它的父进程回收,此时内核将子进程的退出状态传递给父进程,然后抛弃。
- 僵死进程(Zombie):终止了但未被回收的进程。
- 如果父进程没有回收它的僵死进程,那么init进程(pid=1)就会来回收它们。
-
-
让进程休眠
-
加载并运行程序
-
-
信号:一个信号就是一条消息。
-
- 信号->目的进程,两步骤
- 发送信号
- 检测到一个系统事件,比如除零错误或者子进程终止。
- 进程调用了kill函数,显式地要求内核发送信号给目的进程。进程可以发送信号给它自己。
- 接收信号
- 目的进程接收信号:目的进程被内核强迫以某种方式对信号的发送做出反应
- 进程可以忽略,or终止,or捕获信号(通过信号处理程序这个用户层函数)。
- 另外,不包括在以上两步骤里的,待处理信号:只发出而没有被接收的信号。在任何时刻,一种类型至多只会有一个待处理信号。一个待处理信号最多只能被接收一次。内核为每个进程在pending位向量中维护着待处理信号集合,而在blocked位向量中维护着被阻塞的信号集合。
- 发送信号
- 发送信号:发送信号机制基于进程组
- 接收信号
- 信号->目的进程,两步骤
-
- 信号处理问题
- 待处理信号被阻塞:Unix信号处理程序会典型地阻塞当前处理程序正在处理的类型的待处理信号。
- 比如,假设一个进程捕捉了一个SIGINT信号,并且当前正在运行它的SIGINT处理程序。
- 如果另一个SIGINT信号传递到这个进程,那么这个SIGINT将变成待处理的,但是不会被接收,直到处理程序返回。
- 待处理信号不会排队等待:任意类型至多只有一个待处理信号。关键思想是存在一个待处理的信号仅仅表明至少已经到达了一个信号
- 如果有多个类型为k的信号传送到一个目的进程,此进程正在执行k的处理程序,此时k是阻塞的,那第二个信号就被简单地丢弃。
- 系统调用可以被中断:慢速系统调用——像read、write和accept这样的系统调用潜在地回阻塞进程一段较长的时间(回忆上文,read需要等待一段时间,让页从磁盘到缓存里)。在某些系统中,当处理程序捕捉到一个信号时,被中断的慢速系统调用在信号处理程序返回时不再继续,而是立即返回给用户一个错误条件,并将errno设置为EINTR。
- 由于以上信号的特点:信号不能用来对其他进程中发生的事件计数。
- 待处理信号被阻塞:Unix信号处理程序会典型地阻塞当前处理程序正在处理的类型的待处理信号。
- 可移植的信号处理 sigaction
- 显示地阻塞信号 sigpromask
- 对于同步父子进程很方便
- 子进程继承了父进程的被阻塞集合。
- 非本地跳转
- setjmp函数只被调用一次,但返回多次——一次是当第一次调用setjmp,而栈的上下文保存在缓冲区env中时;一次是为每个相应的longjmp。另一方面,longjmp函数只被调用一次,但从不返回。
- 重要应用:允许从一个深层嵌套的函数调用中立即返回,通常是由检测到某个错误情况引起的。
- 信号处理问题
6.操作进程的工具