跳到正文
全部文章

Linux进程/线程的相关概念梳理

建立 Linux 进程、线程模型、轻量级进程、内核与用户线程、协程和纤程的概念脉络。

Linux 的线程模型

Linux 诞生以来出现过三种线程模型:

  1. LinuxThreads:最早的模型,只实现了部分 POSIX Threads 标准。
  2. NGPT:Next Generation POSIX Threads,现已终止。
  3. NPTL:Native POSIX Thread Library,从 2.6 内核开始沿用至今的模型。

在 NPTL 中,Linux 使用用户线程与内核线程一一对应的 1:1 模型。Windows、Solaris、NetBSD、FreeBSD、macOS 和 iOS 等许多系统也采用这种模型。与 N:1 和 M:N 相比,1:1 模型的实现更简单。

通过 pthread 库创建线程时,pthread_create 会调用 clone 系统调用,最终创建一个 LWP(轻量级进程)和一个内核线程。在 NPTL 的 1:1 模型中,一个轻量级进程对应一个内核线程。该 LWP 在内核态拥有对应的 task_struct(进程描述符),是一个独立的线程调度单元。

Linux 的进程与线程

对于系统而言,进程和线程并没有严格区分。创建进程与创建线程都使用 fork 系统调用,只是传参不同。例如,子进程拥有独立的地址空间,而线程共享地址空间。内核调度的单位是 task

可以认为,Linux 中的线程本质上是一组共享资源的进程。

LWP、用户线程与内核线程

LWP(lightweight process,轻量级进程)本质上是一种由内核支持的用户线程。

内核线程只访问内核空间,并共享相同的内核页表。所有内核线程的内核空间相同,而不同进程中的用户线程拥有各自的地址空间。

用户线程在标准定义中完全建立在用户空间。它的创建、同步、销毁与调度都在用户空间完成,不需要内核协助。这个定义与 LWP 存在一定交叉。

上下文切换

一个被抢占的 LWP 需要在用户态保存当前寄存器,切换到内核态后再保存对应内核线程的寄存器。恢复调度时需要分别恢复两个现场,至少涉及两次栈切换,并会造成一定程度的缓存失效。

Green threads

绿色线程是由运行时库或虚拟机调度的“线程”,完全在用户空间中管理。

JDK 1.2 之前,Java 在 Solaris 等平台上实现的线程模型属于绿色线程。早期的 Linux 线程模型也属于这一类型。常见的类似实现主要是协程,例如 Java 的 Quasar 和 Python 的 Greenlet。

Coroutine

协程是为非抢占式多任务处理而泛化的子例程,本质上是一种程序控制机制。协程可以有多个入口点,并在指定位置挂起和恢复执行。

协程分为两类:

  • 非对称协程:协程之间存在调用链,通过 resumeyield 两种操作传递程序控制权。一个非对称协程可以视为从属于它的调用者。
  • 对称协程:只通过一种操作传递程序控制权,例如 coroutine.transfer

Fiber

Fiber(纤程)基本可以认为是带有调度器的有栈协程实现。

Java 创建的线程是什么线程

Java 1.2 以前的部分实现使用 Green threads。1.2 以后,以 Linux 平台为例,线程创建最终调用 pthread_create,属于内核级线程。细节参见这里

参考资料

  1. Light-weight process
  2. Thread (computing)

原文发布于 SegmentFault