CSAPP阅读笔记-第八章
CSAPP 第八章 异常控制流
- 异常
- 进程
- 系统调用和错误处理
- 进程控制
- 信号
- 非本地跳转
- 操作进程的工具
###读前感: 看标题以为是关于程序的异常捕获之类的,非本地跳转应该就是longjmp,信号也有所了解,但是不知道和异常有什么关系。
###读后感:
-
异常
原来这里说的异常含义很广,包括各种硬件上的,操作系统级的,用户级的,异常是一种机制,打破常规顺序执行的机制,异常有四种,中断,陷阱,故障,终止。中断可以理解为IO设备的信号,陷阱最常见的就是系统调用,是故意为之的,用户程序通过系统调用访问内核的一些服务,比如读文件。故障和终止简单理解都是遇到问题了发生的,区别是处理方式有所不同。 -
进程和进程控制
进程是程序的运行实例,我们的程序或软件是放在磁盘上的可执行文件,只有程序真正运行了,开始被CPU调度,占用一定的内存,有运行时的上下文,这样一个整体才叫做进程,多个进程之间互不影响,除非程序使用一些通信手段,否则两个进程相互独立。由于CPU的时钟周期很快,远远快于大多数程序的运行,因为程序有时候会遇到一个很慢的操作,比如IO,比如等待网络数据包,这时CPU如果和程序一起等,一起阻塞就会很浪费CPU,所以一般现代操作系统都提供一个调度算法,来合理分配CPU的时间片,所以内核的CPU调度模块是可以剥夺一个进程对CPU的占有的,也就是所说的抢占式多任务,操作系统允许你“同时”运行多个进程,因为CPU很快,它可以来回切换,这样对于每个进程来说,它好像是独占CPU的;空间上,由于OS的虚拟内存模型,对于每个进程来说,它好像也是独占主存的,当然这些都是硬件和OS的高度配合才做到的,这样整个OS的任务就是,启动的时候加载它自己所需的基本程序,比如init进程,之后整个OS的运行就是和用户交互,管理这些系统和用户进程。进程控制很好理解,两个系统函数:fork和exec系列。用过就知道,还有个回收子进程的wait和waitpid。 - 信号
信号可以用来进程间通信,信号我理解就是类似消息,只不过是操作系统规定好了一些特定的消息在特定的时候会触发,比如子进程退出时给父进程发SIGCHLD信号,这个信号就发这个,你改不了,而且没有信号队列,同一时间只能存在一个,比如发了一个SIGCHLD,父进程收到调用了一个信号处理函数,没处理完其他子进程又发了一个,那么第二个信号会变成待处理信号,直到信号处理函数返回。这期间,任何的第三个第四个第N个SIGCHLD信号就算再发给父进程,也不会被处理,会被丢弃!对于一个信号有四种处理方式:- 进程终止
- 进程终止并存盘
- 调用信号处理函数
- 忽略
第二种貌似是产生dump core文件,这个我还不能确定。其余三种都很好理解。每个信号都有默认的处理方式,有系统函数可以修改一个信号的处理方式,当然有的信号不能修改处理方式,比如SIGKILL的处理方式一定是进程终止,无法改变。
-
非本地跳转
两个函数setjmp(jmp_buf env),longjmp(jmp_buf env,int retval)
。很好理解,就是游戏中的标记点,可以在任意的地方调用setjmp,然后从一个地方调用longjmp代码执行流程就会跳到setjmp的地方,setjmp第一次调用放回0表示设置成功,以后每次调用longjmp返回到setjmp时返回的值是longjmp的第二个函数,以标识是从哪里跳过来的,简单理解就是你在长安设了个回城点,你从凤翔飞回长安和从洛阳飞回长安是不一样的,retval就是来标识区分这个。这种跳转要慎重使用,因为它比goto还强大,而且会打断程序的顺序执行,对代码阅读很负面影响,我貌似记得lua源码里是用了,等有时间仔细研究研究它用的场景。 -
操作进程工具
- strace : 打印进程和子进程的系统调用轨迹。
- ps : 列出当前运行的进程。
- top : 实时地当前进程运行状况。
- kill : 就是kill一个进程,杀不死加-9。
- /proc目录 : 文本格式的内核数据结构,比如
cat /proc/cpuinfo
。