1.控制流:控制转移序列。
2.控制转移:从一条指令到下一条指令。
3.异常控制流:现代操作系统通过使控制流发生突变来对系统状态做出反应,这些突变称为异常控制流。
2、异常处理
异常类似于过程调用,但有一些重要的不同之处。一旦硬件触发了异常,异常处理程序则由软件完成。
a)中断处理:异步是指硬件中断不是由任何一条指令造成的,而是由外部I/O设备的事件造成的。
b)陷阱和系统调用:系统调用是一些封装好的函数,内部通过指令int n实现。
陷阱最重要的用途是提供系统调用。系统调用运行在内核模式中,并且可以访问内核中的栈。
系统调用的参数是通过通用寄存器而不是栈来传递的,如,%eax存储系统调用号,%ebx,%ecx,%edx,%esi,%edi,%ebp最多存储六个参数,%esp不能用,因为进入内核模式后,会覆盖掉它。
在操作系统层:逻辑控制流,私有地址空间,多任务,并发,并行,上下文,上下文切换,调度。
进程就是一个执行中的程序实例。系统中的每个程序都是运行在某个进程的上下文中的。
进程提供给应用程序的关键抽象:a)一个独立的逻辑控制流 ;b)一个私有的地址空间
1、逻辑控制流
程序计数器(PC)值的序列叫做逻辑控制流,简称逻辑流。如下图所示,处理器的一个物理控制流分成了三个逻辑流,每个进程一个。
2、一些概念:
并发流:并发流一个逻辑流的执行在时间上与另一个流重叠。
并发:多个流并发执行的一般现象称为并发。
多任务:多个进程并发叫做多任务。
并行:并发流在不同的cpu或计算机上。
3、私有地址空间
一个进程为每个程序提供它自己的私有地址空间。
运行应用程序代码的进程初始时是在用户模式中的。进程从用户模式变为内核模式的唯一方法是通过异常。
linux提供了/proc文件系统,它允许用户模式进程访问内核数据结构的内容。
4、上下文切换
上下文切换:操作系统内核使用叫上下文切换的异常控制流来实现多任务。
上下文切换:a)保存当前进程的上下文;b)恢复某个先前被抢占的进程被保存的上下文; c)将控制传递给这个新恢复的进程
调度:内核中的调度器实现调度。
当内核代表用户执行上下文切换时,可能会发生上下文切换。如果系统调用发生阻塞,那么内核可以让当前进程休眠,切换到另一个进程,如read系统调用,或者sleep会显示地请求让调用进程休眠。一般,即使系统调用没有阻塞,内核亦可以决定上下文切换,而不是将控制返回给调用进程。
5、用户模式和内核模式
需要限制一个应用可以执行的指令以及可访问的地址空间范围来实现进程抽象,通过特定控制寄存器的一个模式位来提供这种机制。设置了模式位时,进程运行在内核模式中,进程可以执行任何指令和访问任何存储器位置。没设置模式位时,进程运行在用户模式中,进程不允许执行特权指令和访问地址空间中内核区内的代码和数据。用户程序必须通过系统调用接口间接地访问内核代码和数据。
用户程序的进程初始是在用户模式中的,必须通过中断、故障或陷入系统调用这样的异常来变为内核模式。
Linux有一种 /proc 文件系统,包含内核数据结构的内容的可读形式,运行用户模式进程访问。
6、系统调用
在Linux中,可以使用 man syscalls 查看全部系统调用的列表。系统级函数遇到错误时,通常返回-1,并设置全局变量 errno 。
strace 命令可以打印程序和它的子进程调用的每个系统调用的轨迹。
2、创建和终止进程:
运行。进程在CPU上执行,或等待被执行(会被调度)。
停止。进程被挂起(不会被调度)。收到 SIGSTOP 、 SIGTSTP 、 SIDTTIN 、 SIGTTOU 信号,进程停止,收到 SIGCONT 信号,进程再次开始运行。
终止。进程永远停止。原因可能是:收到终止进程的信号,从主程序返回,调用 exit 函数。
父进程通过调用fork创建一个新的运行子进程:父进程与子进程有相同(但是独立的)地址空间,有相同的文件藐视符集合。
fork 函数调用一次,返回两次;父子进程是并发运行的,不能假设它们的执行顺序;两个进程的初始地址空间相同,但是是相互独立的;它们还共享打开的文件。因为有相同的程序代码,所以如果调用 fork 三次,就会有八个进程。
3、回收子进程:
* 回收:当一个进程终止时,内核并不立即把它从系统中清除。相反,进程被保持在一种已终止的状态中,直到被它的父进程回收。
回收子进程的两种方法:
1.内核的init进程 ;2.父进程waitpid函数
1)如果父进程没有回收它的僵死子进程就终止了,那么内核就会安排init进城来回收它们。init进程的PID为1,并且是在系统初始化时创建的。
2)一个进程可以通过调用waitpid函数来等待它的子进程终止或停止。
waitpid函数有点复杂,默认地(当options=0时),waitpid挂起调用进程的执行,知道它的等待集合中的一个子进程终止。
wait(&status)函数,等价于调用wait(-1,&status,0)
5、让进程休眠:
在操作系统和应用程序之间:进程之间传送信号
一种更高层次的软件形式的异常,称为unix信号,它允许进程中断其他进程。
低层的硬件异常是由内核异常处理程序处理的,正常情况下,对用户进程而言是不可见的。信号提供了一种机制,通知用户进程发生了这些异常。
1、信号处理过程
1)发送信号:内核通过更新目的进程中上下文中的某个状态,发送一个信号给目的进程。发送信号有两个原因:a)内核检测到一个系统事件; b)一个进程调用kill函数,心事发送信号
2)接收信号:,目的进程就接收了信号。进程可以忽略这个信号,终止或者通过执行信号处理程序捕获这个信号。
注意:待处理信号,一种类型的信号只能有一种待处理信号,多余的不会排队,而是会舍掉 ; 信号还可以阻塞。
2、发送信号:/bin/kill , kill函数,键盘,alarm函数
进程组:每个进程都只属于一个进程组,进程组是由一个进程组ID来标识的。默认的,一个子进程和它的父进程同属于一个进程组。
在任何时刻,至多只有一个前台作业和0个或多个后台作业。外壳为每个作业创建一个独立的进程组,一个作业对应一个进程组。
用kill函数发送信号:发送SIGKILL信号
用alarm函数发送信号:发送SOGALARM信号
3、接收信号
进程可以通过使用signal函数来修改和信号相关的默认行为。唯一的例外是SIGSTOP和SIGKILL,它们的默认行为不能被修改。
4、信号处理问题
信号处理有以下特性:
1.信号处理程序阻塞当前正在处理的类型的待处理信号。
2.同种类型至多有一个待处理信号。
3.会潜在阻塞进程的慢速系统调用被信号中断后,在信号处理程序返回时不再继续,而返回一个错误条件,并将 errno 设为 EINTR 。
*对于第三点,Linux系统会重启系统调用,而Solaris不会。不同系统之间,信号处理语义存在差异。Posix标准定义了 sigaction 函数,使在Posix兼容的系统上可以设置信号处理语义。
5、同步流以避免并发的错误
以某种方式同步并交流,从而得到最大的可行的交错的集合,每个可行的交错都能得到正确的结果。
(1)c语言提供了一种用户级异常控制流形式,称为非本地跳转。通过setjmp和longjmp函数来提供。
setjmp函数只被调用一次,但返回多次:一次是当第一次调用setjmp,而调用环境保存在缓冲区env中时,一次是为每个相应的longjmp调用。另一方面,longjmp只调用一次,但从不返回。sig—函数是setjmp和longjmp函数的可以被信号处理程序使用的版本。
换句话,在信号处理程序中进行非本地跳转时应使用 sigsetjmp 和 siglongjmp 。如果 savesigs 非0,则 sigsetjmp 在 env 中保存进程的当前信号屏蔽字,调用 siglongjmp 时从 env 恢复保存的信号屏蔽字。同时,应该使用一个 volatile sig_atomic_t 类型的变量来确保 env 未设置时不被中断。
非本地跳转的一个重要应用就是允许从一个深层嵌套的函数调用中立即返回,通常是由检测到某个错误情况引起的。
非本地跳转的另一个重要应用是使一个信号处理程序分支到一个特殊的代码位置,而不是返回到达中断了的指令位置。
异常控制流发生在计算机系统各个层次,是计算机中提供并发的基本机制。
操作系统层——ECF提供进程的概念。两个抽象:逻辑控制流,私有地址空间。
操作系统和应用程序接口处——应用程序可以创建子进程,信号。
应用层——非本地跳转。
1.一开始遇到进程二字,就想到线程,记得上学期Java课程中讲过,但是,不完全清楚二者区别。
解决:进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮。
2.并发和并行
解决:并发行和并行性的区别可以用馒头做比喻。前者相当于一个人同时吃三个馒头和三个人同时吃一个馒头。
前者是逻辑上的同时发生(simultaneous),而后者是物理上的同时发生。
这一章的内容比较多,主要是关于进程控制和进程当中异常处理、信号的使用,课本过一遍之后对这些处理方式仍不能很好地去理解,还需要反复看书。此外,我还遇到了比较容易混淆的名词,看了很多网上程序猿的博客,他们分析的很细致,一些比喻也很形象(比如:并发和并行的比喻)。
《深入理解计算机系统》
http://www.yeolar.com/note/2012/03/22/linux-ecf/
http://www.cnblogs.com/lmule/archive/2010/08/18/1802774.html
http://blog.chinaunix.net/uid-27007072-id-3233727.html