笔者:YY同学
什么是多进程?
多进程是 OS 中一个很重要的概念。进程不同于 Program,与C语言单一的main函数不同,在一个操作系统中可能存在很多个进程,他们各自承担着不同的任务:有的负责运行 QQ、微信,有的负责音乐播放,还有的负责网页访问等等。如果没有多进程,你就不能一边用 MS Word 写作业,一边打开 Bilibili 看视频了。
并行性与并发性
并行性:
是指同一时刻可以执行很多事情,这些事情发生在同一时刻。在 OS 中相当于多个 CPU 同时处理多个不同的事件。
并发性:
往往是指一个东西有同时处理多个事务的能力,这些事情并不是发生在同一时刻,但是发生时刻的间隔非常短。比如 K 同学在 0 至 0.1s 这个时间段内在学习,在 0.1 至 0.2s 这个时间段内在玩手机,然后又在 0.2 至 0.3s 这个时间段内在学习,如此往复…这样看上去 K 同学就像同时在进行学习和玩手机两件事。在OS中相当于一个CPU在不同进程之间进行时间间隔很短的切换,从而实现多个进程的处理。
父进程与子进程
前面介绍了多进程的概念,至于为什么 OS 中会有这么多进程呢?其实他们都是由一个初始进程 init 经过自身不停的复制得到的,这也是计算机开机过程中所做的事情。进程复制的 system call 是 fork(),复制之后进程会从一变成而二,本体的进程称为父进程(Parent Process),复制的进程称为子进程(Child Process)。
Fork 克隆了什么?
fork 的本质是克隆(clone)父进程,因此子进程有些性质是从父进程上衍生出来的,就像孩子会遗传父母的某些特征一样:
此外,fork() 还会克隆父进程的缓冲区(buffer),如果缓冲区有东西则会一起克隆到子进程。【一个很好的例子】
父子进程属性值的对比
-
Fork 返回值:
fork() 函数返回值是一个 int 类型,因为从 fork 这句话开始进程就已经开始复制成两份了,所以对于父进程而言返回值会是子进程的 pid,而子进程的返回值则是 0。 -
PID:
pid 是进程的唯一标识符,每个进程的 pid 都是不一样的。 -
Parent:
父进程是子进程的 Parent,但是如果父进程在子进程之前结束,那么子进程会因为没有 parent 变成孤儿进程(orphan),这个时候 OS 会自动进行 reparent 操作,为子进程寻找一个新的父进程,此时的 parent 对象就会改变。 -
Running Time:
运行时间是从进程创建时刻开始计算的,父进程的运行时间会从程序运行时开始计算,子进程的运行时间会从 fork 时开始计算。
僵尸进程(Zombie)
对于一对父子进程,一般来说父进程需要在子进程结束之后才结束,因为父进程需要释放子进程占用的资源。但有的时候父进程会比子进程结束时间早,这就意味着此时父进程来不及释放子进程的资源,那么在子进程结束后,资源得不到释放,就会一直占用一个进程槽(slot),此时的子进程就会变成一个僵尸进程。一般 OS 结束僵尸进程的方式是使用中断信号(SIGINT),就是键盘上的 Ctrl+C。