1. 程序和进程的区别
首先来看一个故事:
在上述故事中,我们可以抽象出一个简单的计算处理模型:
【程序】就是那本食谱(存储在书架上,一种物理存在,用特定的描述形式阐述做菜的过程和方法)
- 【进程】就是做菜的这一系列活动(动态进行的),包括了洗菜、切菜、炒菜等等
- 【CPU】就是A本人,他是所有操作的执行者
- 【数据】就是西红柿炒鸡蛋的各种原材料,包括了西红柿、鸡蛋...(将一系列数据经由CPU处理变成不同的数据)
2. 进程
2.1 进程的状态
进程就是程序关于某个数据集上的一系列活动。
进程有三个状态,分别是:
- 运行态【running】(actually using the CPU at that instant)
- 就绪态【ready】(runnable; temporarily stopped to let another process run)
- 阻塞态【blocked】(unable to run until some external event happens)
从上图中,我们可以很清楚地看到三种状态之间的转化过程:
- 当发生IO操作时,当前进程就会被阻塞直到IO操作完成
- 当调度器中断当前进程转而执行另一进程,原进程就会处于就绪状态
- 当调度器选择该进程,便会从就绪态转为运行态,享用CPU资源
- 当IO完成后,被阻塞的进程就会转为就绪态,等待操作系统的调度
2.2 进程上下文切换
当进程与进程间因中断(interrupt)或系统调用(system call)时会发生上下文切换
- 正在执行的进程P0由于终端或者系统调用将cpu的使用权交还给os
- os保存P0的PCB信息,并重新从内存中载入P1进程的pcb内容,并执行P1
- P1执行后,由中断或者系统调用由交还使用权给os(调度器scheduler / 调度者scheduler)
- 再回过头来执行P0(载入P0的PCB信息)
上下文切换的代价其实是很高的,需要大量的处理器时间(因此通常使用汇编完成),有时候1秒内可能执行上千次的上下文切换【CONTEXT SWITCH】
即便现代计算机正在逐渐降低上下文切换所占用的CPU时间,但那也仅是在CPU时钟周期降低,处理速度加快的情况下,而不是提升了上下文切换的效率
3. 为什么要引入线程的概念?
既然我们已经有了进程,那么为什么计算机科学家还要搞出一个线程的概念呢?
- 在系统中多应用将同时进行,经常会不断切换状态,通过将一个进程切分成多个线程,达到准并行【quasi-parallel】,程序模型将更简单(这些线程<u>共享地址空间和数据资源</u>,这些能力正是多进程无法做到的(地址空间不同))
- 更加轻量级。比起进程,更加容易(快速)创建和销毁(在一些系统中,比进程创建快10-100倍)
- 性能表现更好。当有大量计算和I/O处理时,线程有能力让这些活动交叠,提升程序的速度
- 对多核处理器更有用。
【注】
由于进程是资源的拥有者,所以在创建、撤销、切换操作中需要较大的时空开销,限制了并发程度的进一步提高。
为减少进程切换的开销,把进程作为资源分配单位和调度单位这两个属性<u>分开处理</u>,即进程还是作为资源分配的基本单位,但是不作为调度的基本单位(很少调度或切换),把调度执行与切换的责任交给“线程”。
这样做的好处不但可以提高系统的并发度,还能适应新的对称多处理机(SMP)环境的运行,充分发挥其性能
3.1 线程的一些缺陷
线程虽然运行速度很快,但并不是十分完美的
主要是在安全性方面的问题:我们知道,进程内的各个线程之间是共享数据和地址空间的,如果其中一个线程出现了错误(比如错误改写了某个变量),其他线程也会跟着出现问题,导致最终整个进程的错误
因此,我们说现在对于进程和线程的使用也是分场合的,不是一味的追求线程:
- 在高性能计算领域(如天气预报、水利、空气动力学等等),这一类需要追求高性能计算,同时程序并不容易出错,就适合使用线程
- 而例如浏览器这种应用,由于浏览器页面的操作由用户执行,有时候会考量到数据安全,因此推荐使用进程,一个进程打开一个网页
3.2 线程的实现
3.2.1 用户空间实现
在用户空间建立线程库,提供一组管理线程的过程由
运行时系统【run-time system】来完成线程的管理工作
内核管理的还是进程,内核不知道线程的存在
线程切换不需要陷入内核
如Unix、Linux
切换速度快 | 一进程只有一个线程运行在处理器上 |
调度算法可以有应用程序设定 | 若一个进程的某个线程调用了阻塞的系统调用,那么该进程的所有线程也将会被阻塞,页面失效也会有同样的问题 |
用户级线程可以运行在任何操作系统,包括不支持线程操作系统 |
3.2.2 内核空间实现
内核管理所有的线程管理,创建,撤销与调度**,并向应用程序提供API
内核维护进程和线程上下文
线程的切换需要内核支持
以线程为基础进行调度
由内核调度,当有多个处理器时,一个进程的多个线程可以在多个处理器上同时执行 | 由内核进行创建,撤销,调度,系统开销更大 |
一个进程的某个线程阻塞不会引起其他线程的阻塞,页面失效同理 |
3.3.3 混合实现
线程创建在——用户空间
线程调度在——内核空间
4. 进程和线程之间拥有资源的关系?
【进程】是资源分配的单位——————【线程】是CPU调度的单位
线程 又称为“轻量级进程”【lightweight processes】
它(同一进程的所有线程)共享进程的地址空间,同时还有自己特有的一些信息:
每个线程共享进程的信息如上图左侧所示
但,每个线程也有自己专属的 <u>PC、寄存器、栈、状态信息</u>
(因为每个线程可能去调用不同的步骤,
因此线程之间都有各自的栈、PC、寄存器,这样防止执行时发生异常)
【注】
- 进程内的多个线程是共存的
- 相互将信息共享,甚至一个线程创建删除另一个线程都是可能的
- 虽然进程之间有上下级关系,但线程间没有(所有线程是平等的)