【问题标题】:Why does the implementation of user level thread (fiber) require a new allocated stack per fiber?为什么用户级线程(光纤)的实现需要为每个光纤分配一个新的堆栈?
【发布时间】:2019-01-03 23:04:03
【问题描述】:

可以使用 setjmp()longjmp() 对 C 光纤进行编码,以在用户级别实现上下文切换。
如中所述 evanjones.caPortable Multithreading(pdf) 还要求每根光纤都有一个新分配的堆栈。
由于纤程存在于线程上下文中,当它被调用时,它会自动关联一个堆栈帧,那么为什么它需要这个新分配的堆栈呢? : 当一根光纤要切换到另一根光纤时,可以使用以下方法:

 cpu_context[N] :global array where the i-th entry is the cpu context(jmp_buffer) of the i-th fiber 

fiber_ith :
   [...]
   if ( setjmp(cpu_context[i]) == 0 ){
        longjmp(cpu_context[j])
   }
   [...]

新堆栈的必要性是因为正如 here 所写的那样,不可能使用 longjmp() 回到从 Fiber 调用的那一刻起堆栈帧不再有效的 Fiber 执行longjmp()?

编辑:这些光纤必须是非抢占式的,并且可以自愿从一根光纤切换到另一根光纤

【问题讨论】:

  • 这个问题是基于错误的前提。 longjmp 不能这样用。

标签: c multithreading stack fiber


【解决方案1】:

假设光纤有一个函数调用另一个函数,该函数调用另一个函数,然后导致该光纤切换到另一根光纤。当我们恢复这个纤程时,我们需要确保所有局部变量都恢复到纤程切换时的状态,并且我们需要确保从这个函数返回到调用函数。 因此出现了以下规则:

  1. 在光纤运行时,它可以更改其堆栈。
  2. 恢复光纤后,堆栈必须回到光纤切换时的位置。

从这两条规则可以立即得出,每根光纤都必须有自己的堆栈。

【讨论】:

  • getcontext 保存当前上下文,因此当您想切换到另一根光纤时,可以使用它来保存当前光纤的上下文。然后你找到你想要切换到的光纤的保存上下文,并通过调用setcontext切换到它。创建新纤程时,您还分配了一个新堆栈并使用该堆栈初始化新纤程的上下文。这样,每根光纤都有自己的堆栈,因此一根光纤不会破坏另一根光纤堆栈上的东西,因此光纤堆栈上的所有东西都保持完整,并且在您切换回它时可以再次使用。
  • @nos,完善新分配的堆栈,可以正确使用 setjmp 和 getjmp,因为它不会像简单堆栈帧那样自动销毁
  • @Neo 如果你使用的是getcontext/setcontext,那么你就不用setjmp了(注意没有getjmp函数)。
  • @nos,对不起,我在开头setjmp()和longjmp()的时候想说错了
  • 当然可以,但你对这些都没有用。
【解决方案2】:

首先,线程不打算手动控制自己的调度。也就是说,并不打算让一个线程决定结束或暂停其执行并启动另一个线程。相反,线程可以同时运行,系统可以同时在不同的物理或虚拟处理器上运行多个线程,或者可以启动和停止线程,以便它们共享处理器上的可用时间。

因为线程可能同时运行,所以它们必须有单独的堆栈。每个线程可能在更改和使用自己的堆栈的同时,其他线程正在更改和使用它们的堆栈。这些堆栈必须分开以避免冲突。

其次,setjmplongjmp 不适用于在线程状态下跳转到任意点。程序可以使用longjmp 仅返回到其当前调用堆栈中的前一个setjmp,在同一个线程中。例如,你不能做一些工作,记住状态Asetjmp,做更多的工作,记住状态Bsetjmp,然后将longjmp 状态A,然后再记住@987654331 @声明B。在longjmpA 之后,B 不再可用——setjmp 为其保存的任何内容都不再有效。

【讨论】:

  • 谢谢,有了新的栈,setjmp() 和 longjmp() 无论如何都必须用来实现上下文切换,对吧?但是栈帧的优点是它不会在一个longjmp()?
  • 我忘了说光纤必须是非抢占的,但可以自愿从一根光纤切换到另一根光纤
  • @Neo: setjmplongjmp 不用于上下文切换。 longjmp 只是一个“长返回”——它返回到 current 调用堆栈中的前一个点。它与线程无关。这就像从两个或 13 或 50 个函数调用返回,而不仅仅是一个。
猜你喜欢
  • 1970-01-01
  • 2012-12-11
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 2018-10-10
  • 2017-07-31
  • 2016-02-16
  • 2020-05-03
相关资源
最近更新 更多