2013-12-08 35 views
2

对于用户级线程,在单个内核线程上运行N个用户级线程。这与只有一个用户线程在内核线程上运行的pthread相反。如何在Linux中为用户级线程实施抢先式调度?

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

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

但是,如何保存和/或突变状态(如寄存器和线程结构)以使这一切工作的细节如何?是否有一个非常简单的用户级线程可用于了解详细信息?

回答

2

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

用户级别的线程有两种调度方式:自愿和抢先。

  • 自愿调度:线程必须定期调用一个函数来使用CPU的传递到另一个线程。这个功能被称为yield()schedule()或类似的东西。
  • 抢先调度:该库强制从一个线程中删除CPU并将其传递给另一个线程。这通常使用定时器信号完成,例如SIGALARM(详情请参见man ualarm)。

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

不幸的是,这些函数从POSIX中删除,所以其他UNIX可能没有它们。如果是这样的话,还有其他的技巧可以完成。最流行的是一个调用sigaltstack()来设置一个用于管理信号的备用堆栈,然后kill()本身进入备用堆栈,longjmp()从信号功能到您想要运行的实际用户模式线程。聪明,呃?作为一个侧面说明,在Windows中,用户模式线程被称为光纤并且也受到完全支持(请参阅文档CreateFiber())。

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

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

并切换从一个UMT到另一个:

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

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

相关问题