系列文章:
操作系统详解(1)——操作系统的作用
操作系统详解(2)——异常处理(Exception)
进程是计算机科学中 最深刻、最成功的概念之一。
进程的经典定义就是一个执行中程序的实例。系统中的每个程序都运行在某个进程的 上下文(context) 中。
以shell为例, 当用户输入一个可执行文件时,shell会创建一个新的进程, 然后在这个新进程的上下文中运行这个可执行目标文件。
在可视化图形操作系统中,当我们双击软件的图标时,发生的是同样的事.
上下文是由程序正确运行所需的状态组成的。
是内核重新启动一个被抢占的进程所需的状态。
包括:
内核可以抢占当前的进程, 并重新开始一个先前被抢占的进程, 这种决策叫做调度, 是由内核中成为调度器的代码处理.
进程之间的切换通过 context switch 实现.
context switch 是较高形式的异常控制流, 以异常处理机制为基础
上下文切换何时会发生?
磁盘取数据要用一段相对较长的时间(数量级为几十毫秒),所以内核执行从进程A到进程B的上下文切换,而不是在这个间歇时间内等待,什么都不做。
在切换之前,内核正代表进程A在用户模式下执行指令.在切换的第一部分中, 内核代表进程A在内核模式下执行指令。然后在某一时刻,它开始代表进程B(仍然是内核模式下)执行指令。在切换之后,内核代表进程B在用户模式下执行指令。
随后,进程B在用户模式下运行一会儿,直到磁盘发出一个中断信号,表示数据已经从磁盘传送到了内存。内核判定进程B已经运行了足够长的时间,就执行一个从进程B到进程A的上下文切换,将控制返回给进程A中.
紧随在系统调用read之后的那条指令。进程A继续运行,直到下一次异常发生,依此类推。
PC存储着CPU将要执行的指令, 多个进程分别有各自的PC. CPU只是按照顺序执行这些指令, 而这个指令序列就是control flow.
并发: Concurrency
一个逻辑流的执行在时间上与另一个流重叠,称为并发流(concurrent flow)
流X和Y互相并发,当且仅当X在Y开始之后和Y 结束之前开始,或者Y在X开始之后和X结束之前开始。
否则,则称为顺序执行.
Tips: 物理意义上, 并发的进程之间并不重叠(执行上是错位的), 但是我们可以看做多个进程之间是平行地在执行.
一个进程和其他进程轮流运行的概念称为多任务(multitasking)。
一个进程执行它的控制流的一部分的每一时间段叫做时间片(time slice) 因此,多任务也叫做时间分片(time slicing).
Attention: 并发流的思想与流运行的处理器核数或者计算机数无关。如果两个流在时间上重叠,那么它们就是并发的,即使它们是运行在同一个处理器上。
作为对比, 阐述并行的定义:
如果两个流并发地运行在不同的处理器核或者计算机上,那么我们称它们为并行流(parallel flow).
当 Unix 系统级函数遇到错误时,
它们通常会返回-1,并
设置全局整数变量 error 来表示什么出错了。
检查错误对程序员是个好习惯
例子:
// 调用Unix fork函数
if ((pid = fork()) < 0) {
fprintf(stderr, "fork error: %s\n",
strerror(errno));
// strerror函数返回一个一个文本串,描述了和某个errno值相关联的错误
exit(0);
}
// 定义错误报告函数, 可以简化代码:
void unix_error(char *msg) /* unix-style error */
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(0);
}
// 进一步包装:
pid_t Fork(void)
{
pid_t pid;
if ((pid = fork()) < 0)
unix_error("Fork error");
return pid;
}
介绍了进程的概念以及并发的内涵,并区分了并发与并行的区别。
下一章将讲解进程的控制,包括子进程的创建(fork), 子进程回收(waitpid), 加载并运行程序(execve)