CSAPP阅读笔记-第八章

CSAPP 第八章 异常控制流
1. 异常
2. 进程
3. 系统调用和错误处理
4. 进程控制
5. 信号
6. 非本地跳转
7. 操作进程的工具

读前感:

看标题以为是关于程序的异常捕获之类的,非本地跳转应该就是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信号就算再发给父进程,也不会被处理,会被丢弃!对于一个信号有四种处理方式:

    1. 进程终止
    2. 进程终止并存盘
    3. 调用信号处理函数
    4. 忽略

    第二种貌似是产生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