线程
# 线程
# 引入线程
首先回忆一下为什么会有进程 —— 在以前,程序是串行执行的,为了让多道程序并发执行,引入了进程。进程虽然显著提高了资源利用率和系统吞吐量,满足了并发的需求,但是这种并发能不能做得更好呢?事实上,进程既是一个携带资源的独立单位,也是独立调度的基本单位,因此,在进程的创建、撤销和切换时,系统必须为之付出较大的时间空间开销。鉴于此,系统不宜设置过多的进程,也不宜频繁地切换进程,这对于并发来说是一种限制。
如何解决这个问题呢?可以把进程看作是管理初创公司的老板,一开始人手不足,老板既要管理公司,也要四处奔跑沟通业务;但是一旦人手充足,那么老板仍然可以管理公司,只是沟通业务的工作就可以交给手下人去执行了。同理,我们可以考虑依然让进程作为拥有资源的独立单位,但是独立调度的基本单位则不再是进程,而是新引入的线程了。
# 线程与进程
调度的基本单位
引入线程后,调度的基本单位不再是进程,而是线程。线程能够独立运行,且切换的时候,代价远远小于进程切换的代价。同一进程不同线程的切换,不会引起进程的切换。
执行的基本单位
我们可以说进程处于 “执行” 状态,但其实指的是该进程的某个线程正在执行;可以说进程处于 “挂起” 状态,但其实指的是该进程的所有线程都被挂起。但我们不能说 “挂起线程”,只能说 “挂起进程”,因为我们只有在无法为进程分配资源时才会将其挂起,而线程并不携带资源,“挂起线程” 没有意义。
并发性
进程间仍然能够并发,不仅如此,同一进程内不需要切换进程运行环境和内存地址空间,一个进程中的多个线程间也能并发,不同进程中的线程也能够并发,系统并发性提升。
资源
资源由进程携带。为了性能考虑,线程仅占有一点必不可少的资源(比如 TCB,程序计数器等)。虽然线程不携带资源,但它可以使用 fork 的进程的资源,即同一进程的线程共享该进程所拥有的资源。另外,这些线程还共享同一片内存地址空间,所以也可以方便地进行通信。
系统开销
在创建和撤销进程时,系统需要分配或者回收 PCB,分配或者回收资源,所以需要付出一定的时空开销;但是同一进程下的各个线程共享内存空间,线程的创建、撤销和通信的时空开销则小很多。
独立性
同一进程中的线程间独立性要比不同进程间独立性低很多。前者独立性高,因为要防止进程之间彼此干扰和破坏;后者独立性低,因为同一进程的多个线程通常需要协作完成任务,互相之间可访问程度相对来说会比较高。
支持多处理机系统
传统的单线程进程,即使处理机再多,一个进程也只能运行在一个处理机上;但是引入了线程后,一个进程的多个线程可以分配到多个处理机上、并行执行。
# 线程的状态
线程的状态有:运行、就绪和阻塞,线程的状态转换也类似于进程。