首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >协作式多任务系统

协作式多任务系统
EN

Stack Overflow用户
提问于 2013-01-19 22:21:56
回答 4查看 7.3K关注 0票数 7

我试图绕过协作多任务系统的概念,以及它在单线程应用程序中的确切工作方式。

我的理解是,这是一种“多任务的形式,其中多个任务通过自愿将控制权让给每个任务中程序员定义的点上的其他任务来执行”。

那么,如果您有一个任务列表,并且一个任务正在执行,那么如何确定将执行传递给另一个任务呢?当你将执行返回到之前的任务时,如何从之前的位置恢复?

我觉得这有点令人困惑,因为我不明白如果没有多线程应用程序,这是如何实现的。

任何建议都会非常有帮助:)

谢谢

EN

回答 4

Stack Overflow用户

发布于 2014-01-01 02:44:40

在单个进程(或执行线程)使用协作多任务的特定场景中,可以使用Windows的fibers或POSIX setcontext系列函数。在这里,我将使用术语纤程。

基本上,当一个纤程执行完一个工作块并希望自愿允许其他纤程运行时(因此称为“协作”术语),它或者手动切换到另一个纤程的上下文,或者更典型的情况是,它执行某种跳到调度器的上下文中的输出()或调度器()调用,然后调度器找到一个新的纤程运行并切换到该纤程的上下文。

我们这里所说的上下文是什么意思?基本上是堆栈和寄存器。堆栈没有什么神奇之处,它只是堆栈指针碰巧指向的一个内存块。程序计数器也没有什么神奇之处,它只是指向要执行的下一条指令。切换上下文只是将当前寄存器保存在某个地方,将堆栈指针更改为不同的内存块,将程序计数器更新为不同的指令流,将该上下文保存的寄存器复制到CPU中,然后进行跳转。Bam,您现在正在使用不同的堆栈执行不同的指令。通常,上下文切换代码是用汇编语言编写的,调用的方式不会修改当前堆栈,或者它会取消更改,在这两种情况下,都不会在堆栈或寄存器中留下任何痕迹,因此当代码恢复执行时,它不知道发生了什么事情。(同样,主题:我们假设方法调用寄存器、将参数推送到堆栈、移动堆栈指针等,但这只是C调用约定。根本不需要维护堆栈,或者让任何特定的方法调用在堆栈上留下任何自身的痕迹)。

因为每个堆栈都是独立的,所以您不会有一些看似随机的方法调用的连续链最终溢出堆栈(如果您天真地尝试使用标准C方法来实现这种方案,则可能会出现这种情况)。您可以使用状态机手动实现这一点,在状态机中,每个纤程都保存其工作位置的状态机,并定期返回调用分派器的方法,但是当实际的纤程/协同例程支持广泛可用时,为什么还要费心呢?

还要记住,协作多任务与进程、受保护的内存、地址空间等是正交的。他们支持独立进程的想法。但是当您让步时,上下文被更改为OS上下文,允许OS调度程序运行,然后可能选择另一个进程进行切换。从理论上讲,您可以拥有一个完全受保护的虚拟内存操作系统,它仍然使用协作多任务。在这些系统中,如果错误的进程从未让步,则操作系统调度程序将永远不会运行,因此系统中的所有其他进程都会被冻结。**

下一个自然的问题是什么让事情变得先发制人..。答案是,OS使用CPU调度一个中断计时器,以停止当前正在执行的任务,并切换回OS调度程序的上下文,而不管当前任务是否关心释放CPU,从而“抢占”它。如果操作系统使用CPU特权级别,(内核配置的)计时器不能被较低级别的(用户模式)代码取消,尽管在理论上,如果操作系统没有使用这样的保护,错误的任务可能会屏蔽或取消中断计时器并劫持CPU。还有一些其他场景,比如IO调用,调度器可以在计时器之外调用,调度器可以决定没有其他进程具有更高的优先级,并在没有切换的情况下将控制权返回给相同的进程...实际上,大多数OSes不会在这里进行真正的上下文切换,因为这样做代价很高,调度器代码在任何正在执行的进程的上下文中运行,所以它必须非常小心,不要跨入堆栈,保存寄存器状态等。

**你可能会问,如果在一段时间内没有调用yield,为什么不直接触发计时器呢?答案在于多线程同步。在合作系统中,您不必费心获取锁,不必担心重新进入等,因为只有当事物处于已知的良好状态时才会让步。如果这个虚构的计时器触发,您现在可能已经破坏了被中断的程序的状态。如果必须编写程序来处理此问题,恭喜...您现在拥有了一个半途而废的抢占式多任务系统。干脆把它做对吧!如果你想改变一些东西,不妨添加一些线程、受保护的内存等等。这就是主要OSes的历史。

票数 7
EN

Stack Overflow用户

发布于 2013-03-30 23:17:56

协作多任务背后的基本思想是信任--每个子任务将以及时的方式自动放弃控制,以避免让其他任务耗费大量的处理器时间。这就是为什么协作多任务系统中的任务需要进行非常彻底的测试,在某些情况下还需要进行使用认证。

我不自称是专家,但我想协作任务可以作为状态机实现,在状态机中,将控制权传递给任务将导致它运行绝对最小的时间,以取得任何类型的进展。例如,文件读取器可能读取文件的下几个字节,解析器可能解析文档的下一行,或者传感器控制器可能只读取一次,然后将控制权返回给协作调度器,后者将检查任务是否完成。

每个任务必须将其内部状态保持在堆上(在对象级别),而不是像传统的阻塞函数或线程那样在堆栈框架上(在函数级别)。

与依赖硬件定时器触发上下文切换的传统多任务不同,协作式多任务依赖于以这样一种方式编写的代码,即保证每个长时间运行任务的每个步骤在可接受的较小时间内完成。

票数 3
EN

Stack Overflow用户

发布于 2013-05-11 13:02:01

这些任务将执行显式的等待、暂停或让出操作,从而调用调度程序。在繁重的计算中,可能存在等待IO完成或显式让步的不同操作。在应用程序任务的主循环中,它可能有一个*wait_for_event*调用,而不是繁忙的轮询。这将挂起任务,直到它有要处理的输入。

还可能存在用于捕获失控任务的超时机制,但它不是切换的主要方式(否则它将不是协作的)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14415303

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档