【问题标题】:How is preemptive scheduling implemented for user-level threads in Linux?Linux中用户级线程的抢占式调度是如何实现的?
【发布时间】:2013-12-08 09:52:22
【问题描述】:

对于用户级线程,有 N 个用户级线程在单个内核线程之上运行。这与只有一个用户线程在内核线程上运行的 pthread 形成对比。

N 个用户级线程被抢先调度在单个内核线程上。但是具体是怎么做的呢?

我听说线程库设置了一些东西,以便内核发送信号,这是将执行从单个用户级线程拉到信号处理程序的机制,然后可以进行抢占式调度.

但是关于如何保存和/或改变寄存器和线程结构等状态以使这一切正常工作的细节是什么?是否有非常简单的用户级线程对学习细节很有用?

【问题讨论】:

    标签: linux multithreading


    【解决方案1】:

    要正确获取详细信息,请使用源代码!但这就是我读它时所记得的......

    有两种方式可以调度用户级线程:自愿和抢占式。

    • 自愿调度:线程必须定期调用一个函数来将 CPU 的使用权传递给另一个线程。此函数称为 yield()schedule() 或类似名称。
    • 抢占式调度:库强制从一个线程中移除 CPU 并将其传递给另一个线程。这通常使用定时器信号完成,例如SIGALARM(详情请参阅man ualarm)。

    关于如何进行真正的切换,如果你的操作系统友好并提供必要的功能,那就容易了。在 Linux 中,您可以使用 makecontext() / swapcontext() 函数轻松地从一项任务切换到另一项任务。同样,请参阅手册页了解详细信息。

    不幸的是,这些功能已从 POSIX 中删除,因此其他 UNIX 可能没有它们。如果是这样的话,还有其他技巧可以做。最流行的是调用sigaltstack() 来设置一个备用堆栈来管理信号,然后kill() 本身进入备用堆栈,以及longjmp() 从信号函数到您的实际用户模式线程想跑。聪明,嗯?

    附带说明,在 Windows 中,用户模式线程称为 fibers,并且也完全受支持(请参阅 CreateFiber() 的文档)。

    最后的手段是使用汇编程序,它几乎可以在任何地方工作,但它完全是系统特定的。创建 UMT 的步骤如下:

    • 分配堆栈。
    • 分配和初始化 UMT 上下文:一个保存相关 CPU 寄存器值的结构。

    从一个 UMT 切换到另一个:

    • 保存当前上下文。
    • 切换堆栈。
    • 在 CPU 中恢复下一个上下文并跳转到下一条指令。

    这些步骤在汇编程序中相对容易完成,但如果没有上述任何技巧的支持,在纯 C 语言中则完全不可能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-16
      • 2013-06-01
      • 2018-06-10
      • 2013-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多