如何在Linux中为用户级线程实施抢占式调度?

时间:2013-12-08 01:31:19

标签: linux multithreading

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

在单个内核线程上抢先调度N个用户级线程。但是如何做到的细节是什么。

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

但是,如何保存和/或改变寄存器和线程结构等状态以使这一切都有效的细节是什么?是否有一个非常简单的用户级线程可用于学习详细信息?

1 个答案:

答案 0 :(得分:3)

要获得正确的详细信息,请使用来源!但这是我读到它时记得的......

可以通过两种方式安排用户级线程:自愿和抢先。

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

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

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

作为旁注,在Windows中,用户模式线程称为 fiber ,并且也完全受支持(请参阅CreateFiber()的文档)。

最后一种方法是使用汇编程序,几乎可以在任何地方使用汇编程序,但它完全取决于系统。创建UMT的步骤如下:

  • 分配筹码。
  • 分配并初始化UMT上下文:用于保存相关CPU寄存器值的结构。

从一个UMT切换到另一个:

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

这些步骤在汇编程序中相对容易,但在没有上述任何技巧支持的情况下,在纯C中完全不可能。