实现用户级线程包

我已经在一个类中负责在C中创建一个用户级线程库。我想知道是否有人可以给我一个事项列表来阅读以实现这一目标。 我对从哪里开始有一个好主意,但是用户级线程上的任何资源以及可能有用的C语言的一些适用方面都非常有价值。

我不清楚如何实现这样的调度程序。 假设我对C语言及其一些更有用的库函数有很好的理解。

我已经完成了这项工作,而没有编写任何汇编程序。 线程切换机制是setjmp / longjmp 。 这涉及为每个线程的堆栈分配内存,然后非常仔细地按摩jmp_buff的值,以便执行跳转到下一个线程的堆栈。

另请参阅Russ Cox非常易读的libtask 。

编辑以响应OP的评论:在决定何时切换线程时,有两个主要方向:抢先和合作。 在抢先模型中,你会有一些类似于定时器信号的东西,它会导致执行流程跳转到中央调度程序线程,该线程会选择下一个运行的线程。 在协作模型中,线程彼此“产生”,或者显式地( 例如 ,通过调用你将提供的yield()函数)或者隐式地( 例如 ,请求由另一个线程持有的锁)。

查看libtask的API以获取合作模型的示例,尤其是函数taskyield()的描述。 这就是我提到的明确收益率。 还有非阻塞I / O函数,其中包含隐式yield – 当前“任务”被暂停,直到I / O完成,但其他任务有机会运行。

一个简单的协作调度程序可以使用swapcontext在C中完成,请查看swapcontext手册页中的示例,这是它的输出:

 $ ./a.out main: swapcontext(&uctx_main, &uctx_func2) func2: started func2: swapcontext(&uctx_func2, &uctx_func1) func1: started func1: swapcontext(&uctx_func1, &uctx_func2) func2: returning func1: returning main: exiting 

所以你可以看到它是非常可行的。

注意:如果你在定时器信号处理程序中交换上下文,那么你自己就是一个先发制人的调度程序,但我不确定这样做是否安全或可行。

编辑:我在sigaction的手册页中发现了这一点,这表明可以在信号处理程序中切换上下文:

如果在sa_flags中指定了SA_SIGINFO,则sa_sigaction(而不是sa_handler)指定signum的信号处理函数。 此函数接收信号编号作为其第一个参数,指向siginfo_t作为其第二个参数的指针,以及指向ucontext_t (cast to void *) 的指针作为其第三个参数。

您可以查看Apple的开源实现。 请注意,代码的最大部分实际上是汇编代码,因为它需要一些您无法在C中执行的特殊操作,例如检索堆栈帧的返回地址或跳转到任意地址。

  • ucontext.h ;
  • getcontext.S ;
  • _setcontext.S ;
  • 更一般地说, 这里的东西 。

用户态线程(通常也称为“光纤”)通常采用协作模型; 也就是说,线程执行直到他们确定他们有足够的时间,然后屈服于另一个线程。 使用优先级队列,您可以实现一个调度程序,该调度程序执行已运行最短时间的任务。 (调度程序会跟踪正在运行的任务,并且当运行任务确定它已经足够时,运行任务会返回。调度程序会更新任务运行的时间,然后生成执行时间最短的任务。)