我正在研究各种OS设计,希望为DCPU-16编写简单的多任务操作系统。但是,我读到的关于抢先式多任务处理的所有内容都以中断为中心。听起来在16位硬件和软件时代,协作式多任务处理更为常见,但这需要考虑每个程序的多任务处理。
有没有办法在无中断架构上实现抢占式多任务处理?我能想到的只是一个可以动态切换任务的解释器,但这会产生巨大的性能损失(如果必须解析每个操作并且不让任何东西本地运行,可能会大约10-20x +,我是想象)。
答案 0 :(得分:4)
抢先式多任务处理通常通过将状态更改/有趣事件发布到调度程序的中断例程来实现,调度程序决定暂停哪些任务,以及根据优先级启动/继续哪些新任务。但是,当正在运行的任务调用OS例程时,可能会发生其他有趣的事件,这可能会产生相同的效果。
但重要的是某些事件会在某处被注明,并且调度程序会决定运行谁。因此,您可以使所有此类事件信令/调度仅在OS调用时发生。
您可以在各种任务应用程序代码中的“方便”点向调度程序添加异常调用,以使您的系统更频繁地切换。无论是仅切换,还是使用一些背景信息,例如自上次调用以来经过的时间,都是调度程序的详细信息。
您的系统不会像中断驱动的系统那样响应,但您已经通过选择所做的CPU来解决这个问题。
答案 1 :(得分:4)
实际上,是的。最有效的方法是简单地修补加载器中的运行时间。内核/守护进程的东西可以有自定义补丁,以提高响应速度。更好的是,如果您可以访问所有源代码,则可以在编译器中进行修补。
补丁可以包含各种分布式调度程序。每个程序都可以打补丁,以获得一个非常低延迟的计时器;在加载时,它将设置计时器,并在每次从调度程序返回时,它将重置它。一种简单的方法将允许代码简单地执行
if (timer - start_timer) yield to scheduler;
不会产生太大的性能影响。主要的麻烦是找到好的点来弹出它们。在每个函数调用之间是一个开始,并且检测循环和插入它们是原始的但是如果你真的需要先响应性地有效。
它并不完美,但它会起作用。
主要问题是确保定时器返回是低延迟;这样它只是一个比较和分支。此外,以某种方式处理异常 - 导致(例如,无限循环)的代码中的错误。从技术上讲,您可以使用相当简单的硬件看门狗定时器,并在不清除任何RAM的情况下在CPU上置位复位;一个in-RAM例程将是RESET向量指向的位置,它将检查和展开堆栈回到程序调用(从而崩溃程序但保留其他所有内容)。它有点像一个暴力 - 如果 - 其他 - 失败的崩溃程序。或者你可以通过这种方式将其改为多任务,将RESET作为中断,但这要困难得多。
所以...是的。它可能但很复杂;使用JIT编译器和动态转换器的技术(模拟器使用它们)。
我知道,这是一个混乱的解释,但我很累。如果不够清楚我明天可以回来清理它。
顺便说一下,在CPU中间程序上声明复位听起来很疯狂,但它是一种历史悠久且经过验证的技术。早期版本的Windows甚至可以运行兼容模式,我认为386是正确的,因为没有办法从16位模式切换回32位。其他处理器和操作系统也做到了。
编辑:所以我对DCPU做了一些研究,哈哈。它不是真正的CPU。我不知道你是否可以在Notch的模拟器中断言重置,我会问他。方便的技术,即。答案 2 :(得分:2)
我认为您的评估是正确的。如果调度程序可以中断(在非变形的字典意义上)正在运行的任务并自动切换到另一个任务,则会发生抢占式多任务处理。因此必须有某种类型的actor来提示调度程序采取行动。如果没有中断设备(在变形的,技术意义上)那么你可以做的很少。
然而,不是切换到完整的解释器,而是发生的一个想法是动态地重新编程所提供的程序代码。因此,在进入流程之前,调度程序知道完整的流程状态,包括它将要输入的程序计数器值。然后,它可以从那里向前扫描,例如,将第二十个指令代码或下一个不立即在程序计数器处的跳转指令代码替换为调度程序。当进程返回时,调度程序将原始指令放回。如果是跳转(有条件或其他),那么它也会适当地影响跳转。
当然,只有程序代码不动态修改自身时,此方案才有效。在这种情况下,您可以对其进行预处理,以便事先知道没有线性搜索的跳转。如果它愿意提名可能被修改的所有地址,那么从技术上讲,你可以允许编写良好的自修改代码,这样你就可以避免在调度程序的动态修改中使用这些代码。
你最终会运行一个翻译,但只能用于跳跃。
答案 3 :(得分:0)
另一种方法是根据事件队列(如当前的GUI应用程序)保留小任务
这也是合作的,但是不需要操作系统调用,只需从任务中返回,然后它将继续执行下一个任务
如果您需要继续执行任务,则需要传递下一个“函数”和指向任务队列所需数据的指针