用户线程为何必须映射到内核线程?

2025年4月29日 | 阅读 6 分钟

内核线程是实际的、能够被处理器调度和执行的线程。用户程序也可以进行自己的调度。然而,这些不是内核线程。每个用户线程都不能独立运行,这就是为什么它需要一个内核级别的线程。

因此,为了让用户级线程取得进展,用户程序必须让其调度器将一个用户级线程映射到一个内核级线程上,然后我们有不同的映射方式来实现这一点。在深入探讨之前,你需要简要了解用户线程、内核线程及其映射。

什么是线程?

线程是计算机系统中 CPU 利用率的基本原子单位。通常我们将进程视为 CPU 利用率的基本单位,但一个进程可以进一步划分为多个执行线程。一个进程可以划分为不同的任务或单元,这些单元可以独立执行,这些单元称为线程。

线程是一个轻量级进程,调度器可以独立管理。它通过并行性提高应用程序性能。线程与其同级线程共享数据段、代码段文件等信息,同时拥有自己的寄存器、堆栈、计数器等。在计算机系统中创建的两种主要线程类型是

  1. 用户线程
  2. 内核线程

线程可以在进程的地址空间内创建,即在进程内核参与下或在没有内核参与的情况下创建。

Why must User Threads be mapped to Kernel Thread

什么是用户线程?

用户线程是由用户借助用户库创建的线程,仅对创建进程及其运行时环境可见,内核不知道这些线程的创建。用户线程仅保留在创建进程的地址空间内,由创建进程在没有内核参与的情况下运行和管理。

用户级线程比内核级线程小且快得多。它们由程序计数器 (PC)、堆栈、寄存器和一个小型进程控制块表示。

优点

用户级线程的一些优点如下:

  • 用户级线程比内核级线程更容易创建,也更快。它们也更容易管理。
  • 用户级线程可以在任何操作系统上运行。
  • 在用户级线程中,线程切换不需要内核模式权限。

缺点

用户级线程存在以下缺点:

  • 用户级线程的多线程应用程序无法利用多处理的优势。
  • 如果一个用户级线程执行了一个阻塞操作,整个进程都会被阻塞。

什么是内核线程?

另一方面,内核级线程由操作系统直接处理,内核负责线程管理。内核管理进程和进程线程的上下文信息。因此,内核级线程比用户级线程慢。

优点

内核级线程的一些优点如下:

  • 同一进程的多个线程可以在内核级线程中的不同处理器上调度。
  • 内核例程也可以是多线程的。
  • 如果一个内核级线程被阻塞,内核可以调度同一进程中的另一个线程。

缺点

内核级线程也存在以下缺点:

  • 从进程中的一个线程切换到另一个线程需要一次模式切换到内核模式。
  • 与用户级线程相比,内核级线程的创建和管理速度较慢。

用户线程如何映射到内核线程

用户线程由线程库映射到内核线程。这种映射方式称为 **线程模型**。

用户线程到内核线程的映射是通过 **虚拟处理器** 完成的。虚拟处理器 (VP) 是一个通常是隐式的库实体。VP 是一个内核线程或库中绑定到内核线程的结构。对于用户线程,VP 表现得像一个 CPU。

存在以下可能的线程模型,所有模型都用于将用户级线程映射到内核级线程。

  1. M:1 模型: 在 M:1 模型中,所有用户线程都映射到一个内核线程。由于进程只有一个相关的内核级线程,因此该进程一次只能运行一个用户级线程。库调度器处理映射,并且该库完全处理所有用户线程编程设施。此模型可用于任何系统,尤其是在传统的单线程系统上。
    Why must User Threads be mapped to Kernel Thread
  2. 1:1 模型: 在 1:1 模型中,每个用户线程映射到一个内核线程。每个用户级线程都在一个单独的内核级线程上执行,或者每个用户线程在一个 VP 上运行。大多数用户线程编程设施直接由内核线程处理。此模型是默认模型。
    Why must User Threads be mapped to Kernel Thread
  3. M:N 模型: 在 M:N 模型中,所有用户线程都映射到一个内核线程池;所有用户线程在一个虚拟处理器池上运行。进程被分配 m 个内核级线程来执行 n 个用户级线程。用户线程可能绑定到一个特定的 VP,就像在 1:1 模型中一样。所有未绑定的用户线程共享其余的 VP。
    Why must User Threads be mapped to Kernel Thread
    这是最高效也是最复杂的线程模型。用户线程编程设施由线程库和内核线程共享。可以通过将 AIXTHREAD_SCOPE 环境变量设置为 **P** 来设置此模型。
  4. 两级: 两级模型类似于 M:N 模型,但它也允许某些用户级线程绑定到单个内核级线程。
    Why must User Threads be mapped to Kernel Thread

在 M:N 模型和两级模型中,内核必须有一种方法与用户级线程管理器进行通信,以维持分配给进程的内核线程的适当数量。这种机制称为 **调度程序激活**。

内核向应用程序提供一组内核线程(虚拟处理器),然后应用程序可以完全控制在每个内核线程上运行哪些线程。内核根据系统中不同进程的竞争需求来控制该集合中内核线程的数量。

内核使用从内核到用户级线程管理器的 **上调** 来通知用户级线程管理器重要的内核事件。

例如,让我们研究一个调度程序激活如何使用的示例。

  1. 内核已为具有 **三个用户级线程** 的进程分配了 **一个内核线程**。
  2. 这三个用户级线程轮流在单个内核级线程上执行。
    Why must User Threads be mapped to Kernel Thread
  3. 正在执行的线程发出 **阻塞系统调用**。
  4. 内核会阻塞被调用的用户级线程以及用于执行该用户级线程的内核级线程。
  5. 调度程序激活:内核决定为该进程分配 **一个新的内核级线程**。
  6. 上调:内核 **通知** 用户级 **线程管理器** 哪个用户级线程现在被阻塞,并且有一个新的内核级线程可用。
  7. 用户级线程管理器将其他线程移动到新的内核线程,并恢复一个就绪的线程。
    Why must User Threads be mapped to Kernel Thread
  8. 当一个用户级线程被阻塞时,
  9. 其他线程可以在新的内核线程上轮流执行。
    Why must User Threads be mapped to Kernel Thread

用户线程为何必须映射到内核线程?

用户线程需要映射到内核线程,因为是内核调度线程在 CPU 上执行,为此,它必须知道它正在调度的线程。

进程创建的所有用户线程都运行在分配给整个进程的同一个内核级线程上。每当该进程轮到在 CPU 上执行时,其内核线程就会被调度到 CPU 上。进程内的所有其他用户线程如果需要执行,都必须逐个映射到分配给创建进程的内核线程上。

由于它们都由创建进程本身控制,因此用户线程必须逐个映射到指定的内核线程,然后才能执行。


下一个主题核心操作系统