【问题标题】:Multithreading model in Linux and WindowsLinux 和 Windows 中的多线程模型
【发布时间】:2026-01-02 08:20:05
【问题描述】:

在过去的几个月里,我一直在学习操作系统课程。但是,我想对我读到的一点进行澄清。据我了解,将用户级线程映射到内核级线程的多线程模型分为三种类型-

  • 多对一模型
  • 多对多模型
  • 一对一模型

我明白为什么多对一模型在并行处理方面效率不高 - 因为阻塞系统调用意味着停止任何处理。
但是,在我所指的《操作系统概念》(Abraham Silberschatz、Greg Gagne 和 Peter Galvin 着)一书中,它说 Linux 和 Windows 家族都使用一对一模型,尽管创建时会产生额外的开销创建的每个用户线程的内核线程。
多对多模型不是更好吗?因为您有许多内核线程,足以具有高度的并行性,并且您始终可以选择两级模型来将用户级线程绑定到内核级线程。

TLDR:尽管 Windows 和 Linux 系统的开销很大,为什么一对一的多线程模型优于多对多模型?

【问题讨论】:

  • 因为在多对多模型中会引入更多开销。 (但是有些架构使用它,尤其是 Goroutines 或 Actors。
  • @eckes 感谢您的快速回复。你能详细说明一下吗?究竟是什么在多对多模型中引入了更多开销?
  • 除了操作系统中的任务调度程序之外,您基本上还必须在软件中实现任务调度程序。这还包括一种切换执行任务或上下文的方法。对于 Actor 模型或无堆栈软件线程,我想第二点问题不大。
  • 至少在 Windows 上,开销是最小的。与默认的用户模式堆栈 1MB 相比,内核堆栈只占用大约三页。大约 1.2%,我猜还有少量的家务。虽然我不是专家,但显然只有一种线程必须极大地简化事情,所以这可能是一个明智的权衡。

标签: linux windows multithreading operating-system


【解决方案1】:

AFAIK,“多对多”模型意味着在用户空间进行调度,因此这意味着每个程序必须在每个内核线程中运行自己的调度程序,使用它在分配给它的用户线程之间共享该线程.换句话说:您需要在每个内核线程中运行诸如 GNU Portable Threads 之类的东西来调度分配给该内核线程的用户线程 (https://www.gnu.org/software/pth/)。

【讨论】:

    【解决方案2】:

    多对多模型不是更好吗?

    我建议再买一本书。 AFAIK 多对多模型完全是理论上的(如果有人知道使用它的系统,请在评论中指出)。这些模型是解释线程的一种非常糟糕的方式。

    在过去,操作系统没有线程的概念。他们安排了执行流程。事实上,许多操作系统仍然是这种情况。

    对线程的需求主要是由需要“任务”支持的 Ada 编程语言驱动的。为了有一个兼容的 Ada 实现,必须有一个库来模拟单个进程中的线程。在这样的系统中,进程安排自己的线程执行(“用户线程”)。这样做的缺点是线程总是交错运行(从不在不同的处理器上并行运行)。

    这被称为“多对一”,但这是对正在发生的事情的糟糕描述。您的模型称“许多用户线程”被映射到单个“内核线程”。实际上,没有内核线程。相反,线程是在进程的上下文中实现的。

    操作系统通常将进程视为具有多个可调度执行线程的地址空间。在这样的系统中,线程是调度的基本单位;不是过程。 Is 是您的方案中的一对一模型。

    它说 Linux 和 Windows 家族都使用一对一模型,尽管为每个创建的用户线程创建内核线程会产生额外的开销。

    这是一种废话。无论线程如何实现,都会产生开销。您经常会发现有人声称“多对一”比“一对一”更有效。这种说法似乎只是都市传说。

    尽管 Windows 和 Linux 系统的开销很大,为什么一对一的多线程模型优于多对多模型?

    “一对一”(又称内核线程)模型更可取,因为它利用了多个处理器并允许实际并行执行。它还避免了某些系统(例如太监)中可能发生的阻塞问题。

    【讨论】:

    • 感谢您的回答!我想我会参考其他一些关于多线程的书。
    • 他们把它弄得太复杂了。