Linux中如何实现用户级线程的抢占式调度?

use*_*220 5 linux multithreading

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

N 个用户级线程被抢占地调度在单个内核线程上。但是如何做到这一点的细节是什么。

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

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

rod*_*igo 5

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

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

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

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

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

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

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

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

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

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

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