野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 20332|回复: 17

[freertos] 分析一下uC/OS-III和FreeRTOS的区别

[复制链接]
发表于 2018-6-10 19:11:46 | 显示全部楼层 |阅读模式
在阅读完uC/OS-III(V3.03.01)和FreeRTOS(V10.0.1)的源码后,我对RTOS有了较深的认识。现将它们之间的一些区别总结出来,有利于大家理解这两个RTOS。


1、uCOS-III中所有的内核对象(如任务控制块、消息队列、信号量等)都是静态创建的,需要用户提供。FreeRTOS中的内核对象支持动态和静态两种创建方法。
(PS: 其实系统提不提供动态创建功能并不那么重要,因为在静态创建的方法的基础上加入内存管理机制,就能自已封装实现动态创建函数)


2、uCOS-III中的任务状态较多,因为它存在“基本状态+挂起状态”这类状态,FreeRTOS中挂起态是个单独的状态。在FreeRTOS中,如果suspend一个正在阻塞的任务,API内部会把任务从相应阻塞表中删除,并将其挂在xSuspendedTaskList上,当该任务被resume后,它就是就绪态,而不会重新返回阻塞态。而uCOS-III中的任务即便在阻塞时被suspend了,它依然处于阻塞态(即等待某个事件发生),如果在suspend的过程中事件发生了,它将解除阻塞态,变为纯粹的挂起态;如果在resume后,该事件仍未发生,它将解除挂起态,变为阻塞态。
(PS: 我感觉uCOS-III中的“挂起”更能称之为“挂起”)


3、为了实现中断和任务的同步,需要在中断中进行post操作,uC/OS-III为了减少中断执行的时间,提高系统中断响应的实时性,设计了OS_TickTask和OS_IntQTask,这样原本在中断里需要进行的一些较为耗时的操作就被放到了任务级代码中执行了。而FreeRTOS并没有这样的设计。
(PS: 我觉得,从这一点上,可以看出uC/OS-III的实时性要比FreeRTOS好。
另外,可能有的同学不理解为什么中断执行时间少了,系统的实时性就好了。这是因为系统实时性的一个关键指标就是中断延迟响应的时间。某个中断可能会被延迟响应的时间,受系统关中断时间的影响,也会受其它同等优先级或者高优先级中断执行时间的影响,所以减少某个中断的执行时间,将有助于减少其它中断的延迟响应时间)


4、uC/OS-III和FreeRTOS的任务切换都是利用的PendSV中断。
         在FreeRTOS的PendSV中断中,它会计算就绪的最高优先级的任务,再去进行上下文切换。而uC/OS-III在触发PendSV中断前,会计算好已就绪的最高优先级的任务,放在OSTCBHighRdyPtr中,这样在PendSV中断中就不用计算就绪的最高优先级的任务是谁了。所以uC/OS-III中PendSV中断的执行时间更短,这有利于提高系统的实时性。


5、uCOS-III的任务操作句柄就是任务控制块TCB的指针。FreeRTOS中单独设置了任务操作句柄这种数据类型,它实质上也是TCB的指针。表面上看,多此一举,但其实这种设计对用户是友好的,用户不需要了解TCB这种内核数据结构的存在,就可以操作任务了。


6、对于时间片轮转调度的功能。
         FreeRTOS是每个时间片(即每个systick中断里)发生同优先级的任务切换。
         而uCOS-III中每个任务能保持的时间片可以单独设置,需要在任务初始化时作为形参传入。这样做的坏处是对用户不太友好(API的形参如果太多,应用开发人员接受起来有些麻烦);这样做的好处是不会在每个时间片都发生任务的切换(任务切换是需要开销的),提高了总的CPU利用率。
         另外,uC/OS-III中,由于可以对每个任务的时间片分别进行设置和修改,所以可以很方便地调节同优先级下每个任务的CPU占用率,尽管两个任务的优先级是一样的,但是有个任务比较重要,我们希望让它的CPU占用率高一点,这时只要把它的时间片设置得大一点即可。而在FreeRTOS中同优先级下的每个任务对CPU的占用率都只能是一样的。


7、uCOS-III内核中的链表大多是不循环的双向链表(有头有尾),在插入和删除操作时,要考虑特殊情况(比如插入表头、插入表尾等特殊情况)。
         而FreeRTOS内核中的链表为双向循环链表,并引入了xListEnd保证了链表永远非空,所以每个元素的插入和删除都是作为表中的一般元素(非表头和表尾)进行的,操作效率要比uC/OS-III高一些。


8、对于修改任务优先级的操作,FreeRTOS和uCOS-III都是可选项。
         对于uCOS-III,在修改任务优先级时,如果任务处于阻塞态,内核会将pend_data从阻塞对象的pend_list上删除,并重新按照新的任务优先级插入,即调用OS_PendListInsertPrio()。
         而FreeRTOS对于修改阻塞态的任务的优先级,似乎只是修改了TCB里的优先级字段就完事儿了,这点虽然不会造成较大的影响,但是违背了“优先级高的任务优先获得阻塞对象”的设计原则。不知这是否是bug。


9、uCOS-III的信号量是没有上限的,只要post,它的信号量值就会增加(不能溢出)。而FreeRTOS中的信号量基于Queue_t实现,其队列容量(uxLength)将作为信号量的上限。


10、uCOS-III支持PendAbort,而FreeRTOS不支持。


11、uCOS-III中的软件定时器是靠对systick分频实现的,与OS_TickTask运行原理类似,都采用的哈希散列表组织定时器。
         FreeRTOS中的定时器是按照超时时间组织成了有序链表。prvTimerTask与LwIP中的tcpip_thread一样,每次都试图按照当前超时链表上的最近超时时间阻塞在queue上。
         FreeRTOS的定时器机制,单独设计了一个queue,所有Timer相关的API(函数或宏)本质上都是对该queue的一次消息投递,由prvTimerTask来完成对消息的解析并处理。这样做的好处就是:只在一个线程中进行与Timer相关数据的操作,省去了互斥带来的开销。


13、uCOS-III的许多API,都设计了OS_ERR* 的参量,它可以用来向应用程序传递许多出错信息,虽然这会增加API的复杂度,给应用程序开发人员带来一些麻烦。比如OSQueuePend,通过&err,我们可以知道这次pend操作是成功还是失败的,如果失败,是怎么失败的(比如:超时、队列被删除、队列被PendAbort等)。有的人可能会说,只要观察函数返回值,就可以知道此次pend操作时成功还是失败的,没必要设置OS_ERR* 这个参量。但是这样做无法得知失败的具体原因。
         FreeRTOS在设计API时就没有设计这个错误参量,应用程序开发人员只能通过API函数的返回值来判断操作是否成功,但是如果失败,则无法得到更多的关于失败的信息。
(PS: 从这一点上可以看出,uC/OS-III提供了更健壮的内核)


14、对于消息队列,uCOS-III只支持出队阻塞,不支持入队阻塞,即OSQueuePost这个函数在消息队列已满的情况下,不会自已阻塞去等待队列里腾出空间,而是直接返回邮箱已满的错误信息,用户需要及时检查返回的错误码,进行处理。
       FreeRTOS中既支持出队阻塞,也支持入队阻塞。
(PS: 在uC/OS-III中尽管不支持post阻塞,但如果必须实现post阻塞(比如LwIP移植中的sys_arch_mbox_post接口实现)也是很容易的,只要利用信号量和消息队列再加上一个阻塞队列专门用来记录等待post的任务即可,这是对uC/OS-III内核进行二次开发)。


15、uC/OS-III使用消息指针代表消息,FreeRTOS使用消息内容的完整备份代表消息,在uC/OS-III中,投递了消息以后,要保证该指针在消息被利用前一直有效(即保证消息内容不被删除、覆盖),在FreeRTOS中则无所谓,另外在FreeRTOS中也可以将消息指针当做消息内容传递,这样就可以模拟出跟uC/OS-III一样的效果了。
   如此看来,FreeRTOS的消息设计更加灵活。但是要注意,使用指针的好处是避免消息的拷贝,这可以提高内核的处理效率,尤其是消息内容较大或者消息需要辗转多个消息队列的时候。所以我觉得像uC/OS-III这样设计就挺好的,没必要考虑其他情况。
   另外,uC/OS-III的消息是以OS_MSG结构体存在的,里面除了消息指针以外,还包含了时间戳,提供了更丰富的信息。不过要注意,由于它使用了OS_MSG结构体承载消息,而OSQueuePost函数内部是通过预先定义好的OS_MSG结构体内存池去获取这种结构的,所以需要用户在编译工程代码时根据自己使用到的消息的规模去配置内存池大小,一些人以为从uC/OS-II过渡到uC/OS-III的好处就是再也不用事先配置每种内存池的大小了(当应用需求变化,总是需要调整,比较麻烦),但千万别忘了有一个(也是唯一一个)内存池需要提前配置好大小。


16、在消息投递时,如果有任务在消息队列的pend列表中等待,uC/OS-III的做法是直接将该消息post给等待的任务并把它就绪,整个消息不会经过消息队列。而FreeRTOS的做法是将该消息放置到消息队列中,然后检查是否有任务正等待接收消息,如果有,就将其就绪,由就绪的任务去主动获取该消息。
       FreeRTOS的做法实现了投递消息与取出消息的解耦,但这带来了一个问题,就是当某个任务投递完一个消息,并使A任务就绪了,而在A任务执行前,又有一个高优先级的B任务从这个消息队列中取出了该消息,那么A任务在以后试图从消息队列中取出消息时,会出现失败,这是FreeRTOS中所有内核对象的pend操作都可能会出现的情况,内核的做法是会重新计算超时时间,只要没超时,就重新阻塞(按新的阻塞时间),这种设计会降低内核的执行效率。在uC/OS-III中,每一次的消息post操作,要么消息被post到了消息队列上,要么消息被post给了任务,操作结果是明确的,操作过程是高效的。
(PS: 我觉得,从这一点可以看出uC/OS-III的内核要比FreeRTOS具有更好的效率、行为可预测性)


17、uCOS-III的pend函数用opt字段区分是try pend还是block pend,如果是block pend,可设置超时时间,如果超时时间为0,则代表永久pend。
         FreeRTOS的pend函数没有opt字段,只有超时字段,如果它为0,则表示不等待,为try pend,如果为其他值,则它为超时时间,如果它为最大值(portMAX_DELAY),并且配置文件中使能了suspend task的功能,则portMAX_DELAY表示永久等待,如果没使能,则表示portMAX_DELAY个ticks将作为超时时间。
         可见FreeRTOS中,在不使能task suspend的情况下,是不允许有任务永久阻塞的(可能是为了应用程序的安全性考虑)。


18、FreeRTOS提供了TaskNotify机制,用它可以更轻便地实现:单对单或多对单的简单同步和通信功能。在uC/OS-III中虽然没有TaskNotify机制,但是提供了TaskSem和TaskQueue机制,可以完成同样的效果。
(PS: 为了跨系统的可移植性,最好不要使用这些特殊机制)



总结:FreeRTOS功能更丰富、更易用;uC/OS-III的实时性更好、效率更高、健壮性更好。
         其实RTOS最主要的功能就是任务调度,其它功能都可以自己开发,难度不大。单独从任务调度器的角色出发去对比这两个RTOS,我觉得uC/OS-III更漂亮、更优秀。
         uC/OS-III通过的安全认证比FreeRTOS要多,FreeRTOS的代码书写是不符合一些标准的。在FreeRTOS的基础上建立了另外两个RTOS:SafeRTOS、OpenRTOS,它们具有更好的安全性,通过了更多的检验和标准,但是与FreeRTOS不一样,需要收费。

         在过去EETimes的RTOS市场占有率调查中,FreeRTOS常年稳居第一,这与它完全免费、开源社区比较活跃的特点有关。再加上FreeRTOS的创始团队现在与亚马逊合作,FreeRTOS的系统功能将更加丰富,将拥有更多商业合作伙伴,用户数量群将继续扩大,目测FreeRTOS的发展前景会更好。

回复

使用道具 举报

发表于 2018-6-11 08:49:35 | 显示全部楼层
东西,谢谢分享。。。。。。
回复 支持 反对

使用道具 举报

发表于 2018-6-11 08:53:45 | 显示全部楼层
谢谢分享
回复

使用道具 举报

发表于 2018-6-11 10:13:45 | 显示全部楼层
你这个是转载还是原创?
回复 支持 反对

使用道具 举报

发表于 2018-6-11 10:28:33 | 显示全部楼层
单独从任务调度器的角色出发去对比这两个RTOS,我觉得uC/OS-III更漂亮、更优秀。

这句我很赞同

还有一点,ucosiii的代码很容易读懂。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-6-11 18:19:08 | 显示全部楼层
fire 发表于 2018-6-11 10:13
你这个是转载还是原创?

完全原创。。
研究生三年,啥事儿都没干,就做了个项目,然后把uC/OS-III、FreeRTOS和LwIP的源码读了个遍
回复 支持 反对

使用道具 举报

发表于 2018-6-16 05:23:27 | 显示全部楼层
楼主分析精辟,收藏了
回复 支持 反对

使用道具 举报

发表于 2018-6-22 10:47:14 | 显示全部楼层
嗯,感觉楼主很了解两个系统的运行机制
回复 支持 反对

使用道具 举报

发表于 2018-6-22 14:21:17 | 显示全部楼层
分析很到位。。。想问下FreeRTOS V10.0版本后有自己的TCP/IP协议栈了,这个原生的是否会比LwIP这个性能要好?
回复 支持 反对

使用道具 举报

发表于 2018-6-23 10:27:13 | 显示全部楼层
谢谢分享!
回复

使用道具 举报

 楼主| 发表于 2018-6-23 17:25:47 | 显示全部楼层
浪花火炎 发表于 2018-6-22 14:21
分析很到位。。。想问下FreeRTOS V10.0版本后有自己的TCP/IP协议栈了,这个原生的是否会比LwIP这个性能要好 ...

我不了解FreeRTOS的TCP/IP协议栈。它才刚出来不久,但是LwIP已经10多年了,得到了较多的验证。

通信协议的设计或者实现,在效率、易用性、可移植性上是相互制约的。

LwIP可以用在有操作系统和无操作系统的环境中,也可以移植到任意的操作系统中,在可移植性上是很好的。由于它提供了回调编程接口,基于RAW API可以开发出超高效的网络应用程序,这种回调编程方式在许多UNIX、Linux的网络服务器中也有用到。缺点是不易使用,开发出来的程序的可读性和可维护性较差。另外,在移植实现了sys_arch.c文件中与操作系统相关的API以后,也可以使用LwIP提供的sequential API或者Socket API进行编程,这种情况下,就跟你使用FreeRTOS TCP/IP或者uC/TCPIP一样了。

基于某个操作系统实现的TCP/IP,在设计时直接使用了该操作系统的各种机制和API,没有预留移植接口,所以它们都只能绑定在该操作系统中使用。这样做也方便了用户,使用户不需要考虑跟许多跟移植相关的问题,只要把网卡的驱动移植正确即可。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-6-23 17:33:24 | 显示全部楼层
本帖最后由 1781748406 于 2018-6-23 17:35 编辑
1781748406 发表于 2018-6-11 18:19
完全原创。。
研究生三年,啥事儿都没干,就做了个项目,然后把uC/OS-III、FreeRTOS和LwIP的源码读了个 ...

至于哪个性能更好的问题,因为我没研究过FreeRTOS TCP/IP,所以无法比较。
如果你使用LwIP,在正确移植和应用的前提下,它的TCP/IP处理过程是没有一丝赘余的,效率很高,性能很好,具体的内核细节我就不说的。你看ESP8266里的TCP/IP固件,华为物联网操作系统Lite OS里面的TCP/IP,使用的都是LwIP,所以性能是不需要担心的。
回复 支持 反对

使用道具 举报

发表于 2018-6-23 18:37:12 | 显示全部楼层
1781748406 发表于 2018-6-23 17:25
我不了解FreeRTOS的TCP/IP协议栈。它才刚出来不久,但是LwIP已经10多年了,得到了较多的验证。

通信协 ...

谢谢你的解答!看来有空我还是多研究LWIP好了
回复 支持 反对

使用道具 举报

发表于 2018-9-20 21:14:17 | 显示全部楼层
能把这两个差异说的这么清晰的人也是了不起
回复 支持 反对

使用道具 举报

发表于 2019-3-6 17:02:29 | 显示全部楼层
只能说优秀,我也需要好好看看源码
回复 支持 反对

使用道具 举报

发表于 2019-3-24 22:28:15 | 显示全部楼层
很赞,谢谢分享
回复 支持 反对

使用道具 举报

发表于 2019-3-25 09:18:13 | 显示全部楼层
nice,楼主很厉害啊,哈哈哈哈,膜拜一下,不止楼主对tls有没有研究,比如配合LwIP使用
回复 支持 反对

使用道具 举报

发表于 2020-6-4 14:33:09 | 显示全部楼层
1781748406 发表于 2018-6-23 17:25
我不了解FreeRTOS的TCP/IP协议栈。它才刚出来不久,但是LwIP已经10多年了,得到了较多的验证。

通信协议 ...

感觉还是硬协议栈比较靠谱
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-4-30 01:29 , Processed in 0.052444 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表