【问题标题】:How user level thread talk with kernel level thread用户级线程如何与内核级线程对话
【发布时间】:2022-10-07 02:13:20
【问题描述】:

我知道操作系统中有三个线程映射模型。

  1. 一对一
  2. 多对一
  3. 多对多

    在这个问题中,我假设我们使用一对一模型.

    假设,现在我重新启动计算机,并且有10内核级线程已经在运行。

    过了一会儿,我决定运行一个 python 程序,它将启动一个具有四个线程的进程。其中三个线程必须运行一个执行系统调用的函数。

    这是一个问题,当我运行 python 程序时,正确的场景是什么。

    a) 当一个python程序启动时,内核会立即在内核空间启动另外4个线程(所以现在内核空间有14个线程)。当用户级的这 3 个线程发起系统调用时,内核会将这些用户级线程映射到内核在 python 程序启动时创建的 4 个内核级线程中的 3 个,这也意味着我们将浪费 1 个内核级线程。

    b) 当一个 python 程序启动时,内核将不会立即在内核空间中启动另外 4 个线程。相反,只要这 3 个用户级线程启动系统调用并准备与内核对话,内核就会创建新的内核级线程。在这种情况下,内核只会创建 3 个线程,这也意味着我们不会浪费任何内核级线程。

    c) 与第二种情况非常相似,但是在这种情况下,当这 3 个用户级线程准备好运行系统调用并与内核对话时,内核将做的是让 3 个已经创建的内核级线程停止执行当前的工作,然后让他们做 python 程序要求内核做的工作。

    这意味着调度程序将选择 3 个随机内核级线程来停止他们正在做的事情,然后将这些任务信息存储到某个地方。之后,调度程序将要求这 3 个内核级线程首先完成 python 程序作业。在这种情况下,我们在内核级别总是只有 10 个线程。

    感谢任何回复和建议的学习材料!

    标签: linux multithreading linux-kernel operating-system


    【解决方案1】:

    内核线程就像一个专门的任务,负责执行特定的操作(并不意味着持续很长时间)。它们不是等待来自用户级线程的传入请求的线程。此外,系统调用不会系统地创建内核线程(有关更多信息,请参阅this post,有关系统调用的一些上下文,请参阅this one):当需要后台任务时启动内核线程,例如处理 IO 请求示例(this post 展示了一个很好的实际案例,尽管描述有点深)。基本系统调用只是在同一个用户线程中运行,但具有更高的权限。请注意,内核函数使用专用的内核堆栈:每个用户级线程在 Linux 上都有 2 个堆栈:一个用于用户级函数,一个用于内核级函数(为了安全起见)。

    因此,在实践中,我认为在通常情况下所有答案都是错误的(即假设目标操作不需要创建内核线程)。如果完成的目标系统调用实际上需要创建内核线程,那么 b) 是正确的答案。确实,内核线程就像前面所说的一次性专用任务。创建/销毁新的内核线程并不昂贵,因为它在内部基本上是一个相对轻量级的task_struct 数据结构。

    【讨论】:

    • 嘿@Jérôme Richard,感谢您的回复。我有以下问题。我发现这个有用的链接:it.uu.se/education/course/homepage/os/vt18/module-4/… 在链接的调度程序激活部分,它说“内核为应用程序提供了一组内核线程(虚拟处理器)”。这正是场景(b)在做什么?
    • 还有一个问题。这是否意味着在通常情况下我们实际上不需要将用户级线程映射到内核级线程。因为我们可以简单地为用户级线程提供更高的权限,然后用户级线程将有很短的时间在内核空间中运行?
    • 随意接受你很清楚的答案;)。
    • @Peter 它显然看起来不像一个过程控制块(这就是我所说的 PCB,就像在系统书籍中一样)。评论指出“palcode 状态”,结构内容似乎无关,而且它似乎只存在于 AFAIK 至少 15 年过时的 Alpha 架构上(根据维基百科,最后一个处理器已于 2004 年发布——即。 18 年前)。
    • 哎呀,你是对的。看起来那个 pcb 结构的成员不是我们所说的 PCB。谢谢!
    【解决方案2】:

    直接回答这个问题。您混合了内核线程和线程。它们不是完全不同的概念,但在操作系统级别略有不同。首先你有thread_infotask_struct。还有一个内存管理上下文。

    对于内核线程,没有内存管理和用户空间分配。内核线程在内核空间中确实有一个单独的堆栈。只有内核代码可以在内核堆栈的上下文中运行,例如通过系统调用代表用户空间。它也可以在中断期间借用;这可能会导致上下文切换。

    最初的 10 个内核线程只是添加到总数中的一个数字。

    b) 当一个 python 程序启动时,内核不会立即在内核空间启动另外 4 个线程。相反,只要这 3 个用户级线程启动系统调用并准备与内核对话,内核就会创建新的内核级线程。在这种情况下,内核只会创建 3 个线程,这也意味着我们不会浪费任何内核级线程。

    这是对的。您的pthread_create() 将使用相同的task_struct,它允许线程共享文件句柄和静态内存。只有用户栈和内核栈不同。线程也共享相同的内存管理结构。这是与完全独立的过程的唯一区别。上下文切换对于线程来说是轻量级的,因为没有可能导致各种刷新的“mm 切换”。这个thread_info 结构可以允许线程在 SMP 情况下存在于不同的内核上。

    thread_info 是内核线程唯一真正的结构/内存。 thread_info 包含在一个 8K 区域(2 页)中,该区域还包含内核堆栈。它是内核唯一的“可调度”实体。堆栈本身包含有关如何返回用户空间的信息,如果它不是内核线程的话。

    对于用户空间,我们有 thread_info 指向的其他结构。因此,至少就thread_info 而言,它是一对一的。

    【讨论】:

      猜你喜欢
      • 2022-08-15
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-08
      相关资源
      最近更新 更多