在用户空间实现线程

2025年7月24日 | 阅读 6 分钟

概述

每个进程都有一个地址空间。每个传统的操作系统都有一个控制流的线程。有时,在同一个地址空间中拥有多个 quasi-parallel 运行的控制流线程是可行的。尽管它们是独立的进程,但它们拥有相同的共享地址空间。

当有多个应用程序同时运行时,有些活动可能会从一个时间点阻塞到另一个时间点,这时就会使用线程。通过分解为多个 quasi-parallel 运行的线程,编程模型变得更简单、更容易。新的元素只能通过线程添加。这种共享相同地址空间和数据的能力对某些应用程序至关重要。

线程没有附加资源。进程创建和销毁很困难,而线程则可以轻松创建和销毁。创建一个线程比创建进程快约100倍。

线程具有程序计数器(pc)来跟踪要执行的下一条指令。它还具有用于保存当前工作变量的寄存器。有一个堆栈用于存储执行历史,其中有一个帧对应一个已调用但尚未返回的过程。

在本文中,您将学习如何在用户空间实现线程,了解其优缺点。

操作系统是程序的集合,它与用户共享计算机系统的硬件和软件资源。它区分用户定义的代码和操作系统代码,以确保不当的应用程序不会损害其他程序或操作系统。其概念是只有在操作系统上运行的任务才能获得硬件支持,这被称为内核模式。相反,在用户程序上执行的任务被称为用户模式。

实现线程包有两种方式:

内核模式是一种特权状态,在这种状态下,进程对所有资源拥有完全控制权,包括硬件、内核数据和操作系统内核代码。
主要区别在于,在内核模式下,内核可以直接访问硬件,而在用户模式下则没有这种情况。然而,当用户程序请求操作系统服务时,系统必须从用户模式切换到内核模式。
  1. 在用户空间
  2. 在内核

1. 用户空间中的线程实现

在此实现模型中,线程包完全在用户空间中,内核对此一无所知。此实现模型的主要优点是,用户级线程包可以在不支持线程的操作系统上运行。例如,用户空间线程包。

2. 内核中的线程实现

在此实现模型中,线程包完全在内核中。不需要任何运行时系统。内核有一个线程表来记录系统中的所有线程。

每次需要创建新线程或销毁现有线程时,都会调用内核。此时,内核线程表会被更新。

线程是一种执行单元,是进程的一部分。它分配进程的资源。调度程序负责调度它。实现线程有两种方法:用户空间或内核空间。

可以在没有内核帮助的情况下在用户空间实现线程。当我们实现用户空间中的线程时,会发生以下情况:

  1. 相应的代码和数据结构存储在用户空间中。
  2. 线程完全由运行时系统处理,内核对此一无所知。
  3. 当调用 API 时,会进行用户空间局部系统调用,而不是直接进行系统调用。

实现线程包的其他方法

以下是另外两种方法:

  • 混合实现
  • 调度程序激活

i) 混合实现

在此实现中,每个内核级线程都有一个用户级线程集,它们轮流使用该线程。

ii) 调度程序激活

调度程序激活工作旨在复制内核线程的工作或功能,但具有更高的性能和更好的灵活性,这通常与在用户空间实现的线程包相关。

弹出式线程

在此系统中,当消息到达时,会立即创建一个新线程来处理该消息,因此称为弹出式线程。

Implement Threads in User Space

这种弹出式线程的好处是它们是全新的,因此不需要堆栈或历史记录寄存器等需要恢复的元素。每个弹出式线程都是崭新的,与其他所有弹出式线程一样。

用户级线程模型

用户空间中的用户级线程可以使用以下四种方法之一来实现:

  1. 一对一
  2. 多对一
  3. 多对多
  4. 两级

在所有模型中,用户级线程都映射到内核级线程。在非线程系统中,内核线程等同于进程。内核线程是内核调度以在 CPU 上运行的执行单元。通常使用虚拟处理器而不是内核线程一词。

一对一

在此一对一模型中

Implement Threads in User Space
  1. 用户空间中的每个用户级线程都在不同的内核级线程上运行。
  2. 内核必须提供系统调用来创建新的内核线程。
  3. 每个用户级线程都映射到一个不同的内核级线程。

多对一

在此多对一模型中

Implement Threads in User Space
  1. 由于进程只关联一个内核级线程,因此用户级线程只能执行一个用户级线程。
  2. 所有用户级线程都可以在同一个内核线程上运行。
  3. 每个用户线程都进行系统调用来创建新的内核线程。
  4. 在内核级别,用户空间中的多个线程被映射到一个线程。

多对多

在此多对多模型中

Implement Threads in User Space
  1. 进程被分配 m 个内核级线程来运行 n 个用户级线程。

两级

在此模型中

Implement Threads in User Space
  1. 它是一个一对一和多对多模型的混合版本。
  2. 单个内核线程只能连接到有限数量的用户线程。

用户空间中实现线程的优缺点

在这里,您将了解用户空间中线程的优缺点。用户空间中线程的一些优点和缺点如下:

优点

  1. 它可以在操作系统不支持内核级线程的系统上执行。
  2. 整个过程快速而高效,因为不需要系统调用。
  3. 组织结构简单,因为线程的创建、切换和控制不会干扰内核。

缺点

  1. 性能可能不稳定。
  2. 它存在调度不佳的问题,例如将进程分配给空闲线程或因线程持有锁而阻塞进程。

常见问题解答:-

为什么多对一线程是用户空间线程的常用术语,该模型对并发和 CPU 使用有什么影响?

一个内核线程映射到多个用户级线程,这就是为什么用户空间线程被称为多对一模型。这意味着无论用户创建多少线程,一次只有一个线程可以访问 CPU。因此,即使在多核系统上,也无法实现真正的并行,这会导致 CPU 使用率低和并发性下降,尤其是在计算密集型应用程序中。用户级线程与内核级线程切换的开销和控制有何不同?

用户级线程中的上下文切换由用户空间线程库独立于内核管理。由于不需要内核调度和模式切换,因此开销较低。内核无法单独调度或优先处理用户线程,因为它不知道它们的存在,这导致对线程执行的控制较少。这可能导致低效的 I/O 操作或系统调用,其中整个进程会被阻塞。

用户空间线程库需要手动实现哪些功能?

线程的创建、手动上下文切换和调度策略(如轮转法或基于优先级的调度)是用户空间线程库的基本功能。线程控制块(TCB)、堆栈分配和同步机制(例如,用于控制阻塞系统调用的互斥锁和信号量)。用户线程必须通过精心设计的库来模拟这些功能,这使得实现既强大又复杂,而内核线程则依赖于操作系统。

阻塞系统调用对用户空间线程有什么影响,有什么典型的补救措施?

在用户空间线程中,内核只看到每个进程的一个线程,并且不区分不同的用户线程。因此,如果一个线程发出一个阻塞系统调用(如从文件或网络套接字读取),则整个进程会被阻塞。这会严重损害并发性和响应能力。开发者通常通过非阻塞 I/O、异步 I/O API 或混合线程模型来应对这种情况,该模型将多个用户线程映射到多个内核线程,从而允许至少一些线程在 I/O 阻塞期间继续执行。