论坛

合作调度

开始于 科奇尼亚 3年前9回复最新回复3年前929意见

最近,在这个论坛上有关于RTOS与裸机的讨论。

我碰巧使用中间的嵌入式系统。它们并不小,但是与最低的Linux支持者相去甚远。为了给您一些实际的数字,我们谈论的是ARM Cortex-M内核,例如20-200MHz时钟,32-512K FLASH和8-128K RAM,通常是某种通信(USB,以太网,RF和/或某些工业通信总线)和一堆用于监视和控制的模拟和数字硬件。在某些系统上,即使是30MHz的芯片也仅在大约10%的时间内忙于做相当简单而无聊的事情,而在另一些系统上,100 + MHz的芯片却在接近90%的时间里在努力地做一些认真的数学运算来推动工作它。

在这些小控件上,我们通常使用协作调度程序。在讨论中没有出现这种可能性,我只是想知道为什么。

如您所知,协作调度是多线程的,其中上下文切换仅在当前线程自愿放弃CPU时才发生,通常是通过调用等待某事的内核函数来进行的。当然,这会带来流氓线程无限期占用CPU的风险。实际上,这是早期Macintosh计算机的问题。他们使用了协作调度,并且编写不当的应用程序可能(并且确实)冻结了整个计算机。

但是我们在这里谈论嵌入式系统。这些线程不是来自未知来源的通用用户应用程序,而是由我们编写的控制功能。它们经常是状态机,以可证明的有限运行时间响应外部事件。即使时间不可预测,我们也可以始终强制某个线程定期将处理器让给其他线程。

从概念上讲,就像超级循环一样,您只需旋转等待某事发生,然后在您调用相关的处理程序后再返回循环。但是,至少对于我来说,我拥有独立的执行线程(以每个线程为单独的堆栈为代价)和用于线程之间通信的标准化工具这一事实吸引着更加简洁,模块化的设计以及更高的代码可重用性。

协作内核为我提供了计时器,事件,信号量,锁和消息。除了每个线程的堆栈损失外,内核的占用空间很小,在FLASH和RAM中均如此。它仅在很短的时间内禁用中断,因此中断延迟不会受到明显影响。与抢先式调度程序相比,它的协作性质具有以下优势:不存在争用条件,并且您不需要不断锁定和解锁每个共享库来保证完整性和状态一致性。 

当然,缺少抢占权也意味着必须将真正时间紧迫的事情下推到ISR中(Cortex-M芯片具有可抢占的优先中断系统),但这是可行的。

从我们的角度来看,对于我们使用的设备,优势大于劣势。协作式调度程序为我们提供了用于设计固件的工具,这些固件具有相互独立的子系统,子系统之间具有定义明确,统一的通信机制,但没有所有竞争问题以及与抢先式调度相关的大多数资源损失。

我想知道,您对此有何看法?

[-]
回覆者 焊点六月4,2018

如果您使用的是带有“真实”线程的RTOS(而不仅仅是如上所述的状态机),则可以采用一种混合方法。线程将协同挂起,但也可能在中断时被强制挂起。在这种情况下,调度程序将在ISR的返回路径中调用。

因此,您不必对时间片进行全面的抢先式调度,但是您可能能够在线程上下文中以相当复杂的动作对中断做出反应,而不必等到之前的工作完成。由于活动是在线程上下文中进行的,因此它是可中断的,因此不会影响IRQ延迟-与在ISR中完成整个工作的解决方案相反。

[-]
回覆者 托姆金斯2018年6月1日

我很高兴您提出了第一个在Motorola 68000系列处理器上运行的Apple OS。有时,他们很痛苦。

话虽这么说,如果苹果公司对每个应用程序都拥有完全的控制权,那么对API使用的控制将更加严格,事情将会变得更好。

那时的计算就像是消费者市场上的狂野西部,每个人都试图从低速CPU和最小内存大小中挤出速度和性能,这也就不足为奇了。

这些苹果系统内部的ROM是操作系统的一半。要调用ROM中的例程,OS或APP将执行非法指令,并且服务向量将指向ROM中的查找表,从中可以很好地加载ROM中的例程地址。由于该操作系统已申请专利,因此复制Macintosh意味着公然侵犯专利。

我同意,协作式多任务处理意味着资源使用的开销较低。堆栈管理和内存分配是有效完成这项工作的关键因素。 ARM家族中的各种功能都在该实现中发挥作用,这些东西早就不存在了。

[-]
回覆者 科奇尼亚六月3,2018

好了,Commodore Amiga拥有抢占式内核,但是由于没有内存保护,糟糕的应用程序仍以Guru Meditation结尾。您不能占用CPU,但是可以覆盖RAM的任何部分。

这让我想起了,我记得当时我看过一本杂志,其中Apple和Commodore都刊登了广告,如果您以正确的顺序阅读他们的口号,那很有趣(至少我是这么认为的): 

Amiga:具有创意思维的计算机

Macintosh:我们其余人的电脑

:-)

[-]
回覆者 普罗旺斯2018年6月1日

关于这个话题的一个很好的转折。就是说,我会看到这样的调度程序实际上是裸机,但是具有API(和/或框架)来支持从一个任务到另一个任务的上下文切换。换句话说,合作框架/ API不必标准化每个“上下文切换”本身,而是标准化了上下文切换机制。我从未使用过,但是会猜测它使编写裸机变得容易得多,并且等效于多线程系统,其中所有线程(=任务)以相同的优先级运行而没有时间片,这意味着它们必须“屈服”。 CPU以允许另一个线程运行。

除了Apple OS,您还能想到其他示例吗?我认为uTasker是其中之一。

鉴于我上面使用的“ CPU”(单数),...多核嵌入式系统又如何?我猜没有没有不能运行Linux(或等效版本)的多核MCU。

[-]
回覆者 科奇尼亚六月4,2018

我相信(但不确定,从来没有成为Windows人士)早期的Windows版本也可以合作。我的意思是在W95之前,例如3.x和更早版本。当我看到Win 1.0在30MHz 286上运行,并带有单色Hercules视频卡时,现在这是最好的非合作式多任务处理。屏幕重新绘制花了很长时间。我在上面打了黑白棋。进行下一步行动比在所述行动后重新绘制桌子花费的时间少得多。


[-]
回覆者 托姆金斯六月4,2018

虽然名称是Windows,但Windows NT是新设计的系统。 Windows NT中的某些基础来自RSX-11M和VMS。 Dave Cutler将DEC留给Microsoft领导Windows NT设计,他过去的经验和知识使之融入Windows NT。

Windows 1.0是一个位于OS-MS-DOS之上的GUI界面。我对MS-DOS不够记得,除了起初不是抢先的。

[-]
回覆者 QL 2018年6月1日

如OP中已经提到的,协作调度尤其适用于运行协作状态机的事件驱动系统。在这种情况下,您甚至不需要显式yield()或上下文切换。每个状态机都以“运行完成”(RTC)的方式自然地处理事件,然后“返回”事件循环。状态机的每次激活都是从事件循环进行的简单函数调用,并在RTC步骤之后返回到事件循环。循环然后可以做出关于接下来要运行哪个状态机的调度决定。这一切都是完全可移植的,不需要上下文切换魔术(按下寄存器并更改堆栈指针)。

这种协作调度程序至少需要一个事件队列,但也可以与多个事件队列一起使用。可以为队列分配优先级(优先级队列),这意味着调度程序始终选择不为空的最高优先级队列。它将事件从该队列中取出,并将其分派到关联的状态机。状态机,事件队列和优先级的这种组合称为“活动对象”。当所有事件队列都为空时,调度程序可能会调用“空闲处理”,它提供了一个集中的位置来将CPU /外围设备置于低功耗模式。

qv_3177.gif

这种协作调度程序的最坏情况任务级别响应是所有活动对象中最长的RTC步骤。这比“超级循环”要好得多,在“超级循环”中,任务级别的响应是循环中最长步骤的总和。

状态机中的大多数RTC步骤自然很短(微秒级),因此任务级响应非常低。但是,有时您需要一些更长的RTC步骤。这里应用的一种模式是将较长的RTC步骤切成更短的片段,从而使调度程序有机会更频繁地运行。要将原始RTC片段链接在一起,活动对象可以将事件发布到self上以触发继续处理(这称为“提醒”模式)。然后状态机可以方便地处理处理的继续。

无论如何,我已经在我的书“ C / C ++中的实用UML状态图,第二版”中的6.3.7节中描述了此调度程序。下面的链接是开始学习更多有关它(以及状态机的其他内核)的一个方便的地方:

//www.state-machine.com/qpc/group__qv.html 

最后的评论是人们经常将事件驱动的状态机与轮询状态机混淆。此处描述的协作调度程序与事件驱动的状态机有关。在``超级循环''中经常看到的轮询状态机需要``尽可能快地''运行并消耗您分配给它们的所有CPU周期。这种轮询状态机需要所有周期,因为它们将事件发现(通过轮询)与事件处理结合在一起。它们显然不适合高效处理。相反,事件驱动的状态机需要将事件发现(在状态机外部发生,通常在中断中发生)与事件的处理(在状态机中发生)分开。事件驱动的状态机需要事件排队。

-彩信 

[-]
回覆者 trogers531六月2,2018

是的,可以按照说明进行操作。处理外部世界的可变性总是存在悬而未决的问题,即使是诸如数据块的大小和性质之类的简单东西也可以将RTC任务扩展到超出预期的范围,但是正如创建者所说的那样,我们应该控制这些限制条件,或者至少在合理程度上充分了解手头工作的性质。

我有那本书,顺便说一句;做得好。强烈推荐。

[-]
回覆者 trogers531六月2,2018

嗯是的,听起来不错。就像我多年来所做的几个系统一样。就像您所描述的那样,它已经成功地构建到了可在罗克韦尔6502变体之一中运行的基于FORTH的系统中,因此时钟和内存限制并没有真正的相关性,乍一看似乎是如此。真正的意义在于代码的组织。

无论感觉到什么回报,所有实时系统都是如此。实时是一种结构性工具,目标是我们,这些人迫切需要一些希望,从逻辑上讲,我们的头脑要凌驾于水面上,并制作出我们可以真正信赖的东西,以做广告宣传。

所以:IMO,您的位置正对。我们将原始的基于6502的代码用于十多个设计中,其中一些在三十年后仍然很强大,直到您坐下来尝试使用IBM PCjr来完成它,这听起来似乎是一件微不足道的工作。我们很久以前就传出的恐怖故事)。

我们尽快将自己的硬件切换到基于68000的硬件,也使用FIG FORTH作为基础,从Motorola浮点(必须在正确之前进行“修复”),68020和-30带有IEEE数学协处理器的硬件,就像那样。与您所描述的类似,我们略过了一点,在系统的基础上添加了商业内核,在本例中为pSOS,这是一小段代码,它增加了更多控制的奢侈,而无需花费太多精力我们的部分包括抢占,易于实现的资源锁定等。

所有这些都是由对实时构造和工具作为组织设备的作用的有意识的认识驱动的,对于那些属于或渴望Knuth的“牧师类”的人(对不起,唐,我知道您希望我们会忘记您说的话;毕竟这仍然是真的。

我也不会避开“支持Linux”的硬件选择。我们现在正在使用Omega2 +设备进行一个项目,并且鉴于特定问题的局限性,这是一个非常有效的方法。我们所拥有的应该是坚实的,能够在入睡时给人一种温暖而模糊的感觉,这可能是使社区中那些疯狂地发布此类内容的成员的唯一有效测试。

我不知道我会从简单的Linux设备中追赶关键调度的需要;这将取决于可用内核原语的坚固程度,芯片组的坚固程度(例如,确定性意义;我假设没有人会费心尝试部署一个flakey硬件),以及获得的回报是多少我们努力使事情变得正确,等等。

您知道的,是平常的东西,正如我在顶部所说的那样,听起来好像您已经扎上了珠子。能够确定代码的关键元素是正确的,在时间上合理的,或者是图片中包含的其他内容,并且对为什么您的观点有效的观点有扎实的了解,这就是所有这些实时内容的含义。

尽管其他人会告诉您“加油”,但还有很多。自从第一个实验性RT系统问世以来,我就一直在观察市场的发展,在会议和用户团体盛会上站起来并使很多好人感到困惑,而事实仍然存在:关于如何正确构造结构原理的例子太多了某人从火中逃脱出来,真的躲开了我的上帝,我们从来没有想过那500磅的东西可能会掉下来,就像那样,说服我做任何其他的事情方式,用于任何其他目的。

顺便说一句,甚至与代码重用无关。那只是肉汁;我从来没有担心过一分钟。它只是自然发生的。

顺便说一句:我前面提到的基于罗克韦尔芯片的系统是整个方法的一个很好的例子。尽管罗克韦尔的确有一个工程演示部分可以引导并运行FORTH环境,但这并不是我们所使用的。我们采用了硬件,并精心设计了自己的硬件,并配有非常有用的实时基础知识,从而可以轻松地将大型复杂的系统以经济的方式少量集成到大型研究机构中。

还有很多其他工程师试图使用罗克韦尔提供的芯片,这让我们感到沮丧和退出,或者产生了“不完美”的结果。那里有大量类似的设备,如BASIC芯片等,注定要进行认真的工作。这种现象经常发生在底层技术的接缝处。每当出现严重的缩水(在尺寸,复杂性等方面向前迈进)时,都会出现大量草草构思的工程演示硬件产品,在大多数情况下,至少应谨慎使用。

坚持下去;从我的角度来看,您对成功需要什么有很好的认识。祝好运。