我试图绕过合作多任务系统的概念,以及它在单线程应用程序中的确切工作方式.
我的理解是,这是一种"多任务处理形式,其中多个任务通过在每个任务内的程序员定义的点上自动将控制权交给其他任务来执行."
因此,如果您有一个任务列表并且一个任务正在执行,那么您如何确定将执行传递给另一个任务?当你将执行恢复到之前的任务时,如何从以前的位置恢复?
我觉得这有点令人困惑,因为我不明白如果没有多线程应用程序可以实现这一点.
任何建议都会很有帮助:)
谢谢
在您的特定方案中,单个进程(或执行线程)使用协作式多任务处理,您可以使用Windows的光纤或POSIX setcontext系列函数.我将在这里使用术语"纤维".
基本上,当一根光纤完成执行大量工作并希望自愿允许其他光纤运行(因此称为"合作"术语)时,它要么手动切换到另一根光纤的上下文,要么通常更多地执行某种产量()或者scheduler()调用跳转到调度程序的上下文,然后调度程序找到要运行的新光纤并切换到该光纤的上下文.
这里的背景是什么意思?基本上是堆栈和寄存器.堆栈没有什么神奇之处,它只是堆栈指针恰好指向的内存块.程序计数器也没什么神奇之处,只是指向下一条执行指令.切换上下文只是将当前寄存器保存在某处,将堆栈指针更改为不同的内存块,将程序计数器更新为不同的指令流,将上下文保存的寄存器复制到CPU中,然后进行跳转.Bam,您现在正在使用不同的堆栈执行不同的指令.通常,上下文切换代码是在程序集中编写的,该程序集以不修改当前堆栈或退出更改的方式调用,在任何情况下它都不会在堆栈或寄存器中留下任何痕迹,因此当代码恢复执行时它具有不知道发生了什么.(同样,主题:我们假设方法调用寄存器,将参数推送到堆栈,移动堆栈指针等,但这只是C调用约定.没有什么要求你维护堆栈或任何特定的方法调用在堆栈上留下自己的任何痕迹).
由于每个堆栈是分开的,因此您没有一些看似随机的方法调用的连续链最终溢出堆栈(如果您天真地尝试使用不断相互调用的标准C方法来实现此方案,则可能是结果).您可以使用状态机手动实现此操作,其中每个光纤保持状态机的工作状态,定期返回调用调度程序的方法,但为什么在实际的光纤/协同支持广泛可用时呢?
还要记住,协作式多任务处理与进程,受保护的内存,地址空间等正交.见证Mac OS 9或Windows 3.x. 他们支持单独流程的想法.但是当你屈服时,上下文被更改为OS上下文,允许OS调度程序运行,然后可能选择另一个进程切换到.理论上,您可以拥有一个完全受保护的虚拟内存操作系统,仍然使用协作式多任务处理 在这些系统中,如果错误的进程从未产生,则OS调度程序从不运行,因此系统中的所有其他进程都被冻结.**
下一个自然的问题是什么使事情先发制人......答案是操作系统安排一个CPU中断计时器来停止当前正在执行的任务并切换回OS调度程序的上下文,无论当前任务是否关心发布CPU与否,因此"预先"它.如果操作系统使用CPU权限级别,则(内核配置的)计时器不能被较低级别(用户模式)代码取消,但理论上如果操作系统不使用此类保护,则错误的任务可能会屏蔽或取消中断计时器,劫持CPU.还有其他一些场景,比如IO调用,调度程序可以在定时器外调用,调度程序可以决定没有其他进程具有更高的优先级,并且在没有交换机的情况下将控制权返回到同一进程......实际上大多数操作系统都没有在这里做一个真正的上下文切换,因为它很昂贵,调度程序代码在任何正在执行的进程的上下文中运行,所以必须非常小心不要踩到堆栈,保存寄存器状态等.
**你可能会问,如果在一段时间内没有调用产量,为什么不直接启动计时器.答案在于多线程同步.在合作系统中,您不必费心去取锁,担心重新进入等等,因为只有当事物处于已知良好状态时才会屈服.如果这个神话计时器触发,你现在可能已经破坏了被中断的程序的状态.如果必须编写程序来处理这个问题,恭喜......你现在有了一个半先出的先发制人多任务系统.不妨做正确的事!如果你正在改变事物,也可以添加线程,受保护的内存等.这几乎就是主要操作系统的历史.
小智 3
协作多任务处理背后的基本思想是信任——每个子任务都会及时地自行放弃控制,以避免占用其他任务的处理器时间。这就是为什么协作多任务系统中的任务需要经过极其彻底的测试,并且在某些情况下需要经过使用认证。
我并不声称自己是专家,但我认为协作任务可以作为状态机来实现,其中将控制权传递给任务将导致它运行取得任何进展所需的绝对最短的时间。例如,文件读取器可能会读取文件的接下来的几个字节,解析器可能会解析文档的下一行,或者传感器控制器可能会进行一次读取,然后将控制权返回给协作调度程序,协作调度程序将检查任务完成。
每个任务都必须将其内部状态保存在堆上(在对象级别),而不是像传统的阻塞函数或线程一样保存在堆栈帧上(在函数级别)。
与依赖硬件计时器来触发上下文切换的传统多任务处理不同,协作多任务处理依赖于以这样的方式编写代码:保证每个长时间运行的任务的每个步骤在可接受的短时间内完成。
| 归档时间: |
|
| 查看次数: |
6809 次 |
| 最近记录: |