进程
早期的计算机只有一个单核CPU,操作系统把进程作为CPU调度单元。进程拥有独立的内存地址空间,那时候还没有线程的概念。
进程有3个状态,分别是阻塞、就绪、运行。当进程所需资源未到位时是阻塞状态,当进程拥有资源但未被CPU调度是就绪状态,当进程用有资源并且被CPU调度了就是运行状态。
用户态线程
随着程序越来越复杂,调度产生的上下文切换也越发昂贵,于是程序员寻思能不能在同一地址空间(Address Space)下,执行多个进程。但操作系统内核出于保护目的,禁止一个进程直接访问另一个进程的地址空间。
既然操作系统不支持,程序员决定在用户空间下维护一张线程表,实现可以自行调度的“进程”,这就是用户态线程,现在一般叫做纤程或协程。
用户态线程的优势有:
- 在用户空间下进行线程切换的速度远快于在操作系统内核中的实现
- 程序员可以自行实现垃圾回收器来回收线程
- 当线程数量过多时,由于在用户空间维护线程表,不会占用大量的操作系统空间
用户态线程的劣势有:
- 由于操作系统不知道线程的存在,因此当一个进程中的某一个线程进行系统调用时,比如缺页中断而导致线程阻塞,此时操作系统会阻塞整个进程,即使这个进程中其它线程还在工作
- 假如进程中一个线程长时间不释放CPU,因为用户空间并没有时钟中断机制,会导致此进程中的其它线程得不到CPU而持续等待
内核态线程
伴随多核CPU的出现,操作系统也开始支持线程了。内核空间维护了一张线程表,线程由内核调度,这就是内核态线程,也称作轻量进程(Light Weight Process,LWP)。今天说的线程,如非指定,都是内核线程。
内核态线程的优势有:
- 当一个线程阻塞时,操作系统可以选择将CPU交给同一进程中的其它线程,或是其它进程中的线程,而对于用户态线程的调度只能在本进程中执行,直到操作系统剥夺了当前进程的CPU
内核态线程的劣势有: - 所有可能阻塞线程的调用都是 System Call,相比在用户空间下造成线程阻塞的 System runtime call,成本高出不少
- 创建和销毁的成本更高。为了降低成本,当一个线程需要销毁时,仅作标记销毁;当需要新建一个线程时,就复用被标记销毁的线程即可
- 接收系统信号的单位是进程,而不是线程,那么由进程中的哪一个线程接收系统信号呢
逻辑核心
“单核CPU 在同一时间内只能够运行一个进程”,在过去很长一段时间是对的,直至同时多线程(SMT)的出现。超标量处理器(1个CPU物理核心)可以同时跑超过一个线程,例如 Intel 的 hyperthreading 支持一个物理核心跑两个线程。讲几核的 CPU的核心数一般指物理核心数,如果是指逻辑核心数一般直接会说线程数,几个逻辑核心就同时支持几套架构状态和几个线程。
“单进程多线程可以同时用到 CPU的双核心”,在主流操作系统上没问题。对操作系统内核而言,直接可见的CPU资源是逻辑核心,可以调度的任务一般直接实现成 CPU支持的线程,所以 单核CPU 可以同时跑多个任务。
不同操作系统中任务的概念不一样:
- Windows 调度的是线程,进程只是线程的容器
- Linux内核 不区分进程或者线程,调度的任务在用户空间可以被实现成一个进程或进程中的线程。
参考
来源:https://www.cnblogs.com/mougg/p/12319733.html