线程的前世今生

一世执手 提交于 2020-02-17 01:02:58

进程

早期的计算机只有一个单核CPU,操作系统把进程作为CPU调度单元。进程拥有独立的内存地址空间,那时候还没有线程的概念。
进程有3个状态,分别是阻塞、就绪、运行。当进程所需资源未到位时是阻塞状态,当进程拥有资源但未被CPU调度是就绪状态,当进程用有资源并且被CPU调度了就是运行状态

用户态线程

随着程序越来越复杂,调度产生的上下文切换也越发昂贵,于是程序员寻思能不能在同一地址空间(Address Space)下,执行多个进程。但操作系统内核出于保护目的,禁止一个进程直接访问另一个进程的地址空间。
既然操作系统不支持,程序员决定在用户空间下维护一张线程表,实现可以自行调度的“进程”,这就是用户态线程,现在一般叫做纤程协程
用户态线程的优势有:

  1. 在用户空间下进行线程切换的速度远快于在操作系统内核中的实现
  2. 程序员可以自行实现垃圾回收器来回收线程
  3. 当线程数量过多时,由于在用户空间维护线程表,不会占用大量的操作系统空间

用户态线程的劣势有:

  1. 由于操作系统不知道线程的存在,因此当一个进程中的某一个线程进行系统调用时,比如缺页中断而导致线程阻塞,此时操作系统会阻塞整个进程,即使这个进程中其它线程还在工作
  2. 假如进程中一个线程长时间不释放CPU,因为用户空间并没有时钟中断机制,会导致此进程中的其它线程得不到CPU而持续等待

内核态线程

伴随多核CPU的出现,操作系统也开始支持线程了。内核空间维护了一张线程表,线程由内核调度,这就是内核态线程,也称作轻量进程(Light Weight Process,LWP)。今天说的线程,如非指定,都是内核线程
内核态线程的优势有:

  1. 当一个线程阻塞时,操作系统可以选择将CPU交给同一进程中的其它线程,或是其它进程中的线程,而对于用户态线程的调度只能在本进程中执行,直到操作系统剥夺了当前进程的CPU
    内核态线程的劣势有:
  2. 所有可能阻塞线程的调用都是 System Call,相比在用户空间下造成线程阻塞的 System runtime call,成本高出不少
  3. 创建和销毁的成本更高。为了降低成本,当一个线程需要销毁时,仅作标记销毁;当需要新建一个线程时,就复用被标记销毁的线程即可
  4. 接收系统信号的单位是进程,而不是线程,那么由进程中的哪一个线程接收系统信号呢

逻辑核心

“单核CPU 在同一时间内只能够运行一个进程”,在过去很长一段时间是对的,直至同时多线程(SMT)的出现。超标量处理器(1个CPU物理核心)可以同时跑超过一个线程,例如 Intel 的 hyperthreading 支持一个物理核心跑两个线程。讲几核的 CPU的核心数一般指物理核心数,如果是指逻辑核心数一般直接会说线程数,几个逻辑核心就同时支持几套架构状态和几个线程。

“单进程多线程可以同时用到 CPU的双核心”,在主流操作系统上没问题。对操作系统内核而言,直接可见的CPU资源是逻辑核心,可以调度的任务一般直接实现成 CPU支持的线程,所以 单核CPU 可以同时跑多个任务。
不同操作系统中任务的概念不一样:

  • Windows 调度的是线程,进程只是线程的容器
  • Linux内核 不区分进程或者线程,调度的任务在用户空间可以被实现成一个进程或进程中的线程。

参考

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!