进程
有了进程之后,即使 cpu 只有一个,但是他们也有并发的能力,它们将单独的 cpu,变换成多个虚拟的 cpu,就好像每个程序进程都有自己独占的 cpu 一样。
一个进程是一个正在执行的程序实例,包括程序计数器、寄存器、变量的当前值,从概念上来说,每个进程都有自己虚拟的 cpu。
虚拟 cpu 的实现方式是,cpu 由一个进程快速切换到另一个进程,每个进程运行几十或几百毫秒,严格来说,在某一瞬间,单核 cpu 只能运行一个进程。
创建
场景
- 操作系统启动的时候创建
- 一个正在运行的进程,通过系统调用,创建新的进程协助工作。
- 在交互式系统中,输入一个命令,或者双击图标,可以启动一个程序,开启一个新的进程
从技术角度来说,新进程,都是由已经存在的进程,通过系统调用来创建的。
- 在 unix 中,通过 fork 调用,这个系统调用会创建一个和调用进程相同的副本。父子进程拥有相同的内存镜像、同样的环境字符串、同样的打开文件。通常,子进程会接着执行 execve 系统调用,来修改内存镜像,并运行一个新的程序
- windows 中,可以通过调用 CreateProcess 来创建新的进程
在 windows 和 unix 中,进程创建后,父进程和子进程拥有不同的地址空间,如果某个进程在它的地址空间修改了个字,其他进程是不感知的。
- 在 unix 中,子进程的地址空间是父进程的镜像,读的时候是可以共享的,如果要写的话,就会写时复制,写的内容会写到自己的私有空间。
- 在 window 中,创建子进程的时候,就是不同的地址空间。
终止
场景
- 程序逻辑自己在正常退出。
- unix 中,调用 exit,或者界面上的一些退出菜单项
- window 中的,ExitProcess 调用
- 严重错误异常退出,致命错误,进程会收到中断信号
- 被其他进程杀死
- 例如 unix 中的 kill 命令
- window 中的 TerminateProcess 调用
层次结构
一个进程,可以有 0 个,或者多个子进程。
- 在 unix 中,系统启动的时候,有一个 init 特殊进程,然后这个进程开始创建其他子进程,子进程再创建其他进程。就形成了一个树状结构,init 进程就是根
- windows 中没有进程层次概念,所有进程地位都是相同的
进程的状态
尽管每个进程是一个独立的实体,有自己的程序计数器和内部状态,但是进程之间需要有相互作用通信,例如
cat a.log b.log | grep ERROR
有可能 grep 已经准备就绪可以运行,但是输入还没完成,这个时候必须阻塞 grep。
进程的 3 种状态
- 运行态,该时刻实际占用 cpu
- 就绪态,可以运行,但是因为 cpu 正在运行其他进程,暂停着
- 阻塞态,除非某种外部事件发生,否则不能运行,监听事件触发
进程的实现
操作系统维护一张表格,即进程表。每个进程占用表格的一行,每行里有该进程的重要信息,例如状态,程序计数器,堆栈等。
线程
每个进程有一个地址空间和一个控制线程。随着技术发展,一个进程下有多个线程。
进程用于把资源集中在一起,线程是被 cpu 调用执行的实体。
同一个进程中并行运行多个线程,是对一台计算机中并行运行多个进程的模拟。
- 前一种:多个线程共享进程里的地址空间和其他资源
- 后一种:多个进程,共享计算机的物理内存和其他硬件资源
多线程的优势
- 多个线程之间可以共享地址空间,进程地址空间是独立的
- 线程比进程轻量,cpu 切换多线程速度快
多线程和进程共享的内容
进程中被线程共享的 | 线程中独立的内容 |
---|---|
地址空间 | 程序计数器 |
全局变量 | 寄存器 |
打开文件 | 堆栈 |
子进程 | 状态 |
账户信息等 |