• RTOS任务间通信为什么不用全局变量?


    关注+星标公众,不错过精彩内容

    4c02a9e4acac3cad305f9e72fa36b1f7.gif

    作者 | strongerHuang

    微信公众号 | strongerHuang

    有深入理解RTOS原理,或阅读过RTOS源码的同学应该知道:RTOS实现任务间通信通常是由一系列指针进行操作实现的。

    任务间通信的“有效数据”,其实也是由指针指向一个“变量”或“数组”实现的。

    1.信号量

    信号量,本质是传递一个“事件”。比如:任务A完成发送数据,通过信号量通知任务B。

    OSSemPost(EventSem_SendOK);

    我们主要想传递“完成发送数据”这个“事件”,进一步分析,其实就是一个“标志”或“变量”

    2.队列

    队列和信号量原理类似有点类似,只是这里是“变量”。比如:串口接收完成一帧数据,通过队列发送给任务B.

    OSQPost(UARTRcvQueue, RcvBuf);

    相比信号量,队列传递的数据量更大,队列传递的有效数据一般是“数组”。

    还有邮箱,与队列类似,可以理解为“二维数组”。

    写到这里,你会发现,不管信号量,还是队列,底层本质也是传递“变量”“数组”。

    那么问题来了:RTOS任务间通信为什么不用全局变量?

    这个问题比较常见,也看到在我的技术交流群有讨论,所以就简单来分享一下看法。

    全局变量有什么问题?

    RTOS任务间通信为什么不用全局变量?原因在于使用全局变量存在诸多弊端。

    1.抢占问题

    两个或多个任务,都要去“使用”同一个全局变量,如果不添加任何“互斥”措施,必定会存在抢占的问题。

    2.代码规范问题

    整个项目只有少数几个全局变量没什么问题,如果是整个项目有几十个,甚至几百个全局变量,你觉得这样的代码,后面好维护吗?

    经过多次迭代,代码只会越来越难理解,越来越难阅读。

    3.耦合性问题

    全局变量会导致分层不合理与模块化编程相违背,你的全局变量没有归属,既不是任务A,也不是模块A,最终可能“任人宰割”导致“夭折”。

    4.安全性问题

    有一句话怎么说的呢,全局变量是项目的“罪魁祸首”,项目做大之后,一旦有小修改,可能就会引发大Bug.

    3c2845bbd0ae92c49b432420b8ce4df1.gif

    全局变量还有很多弊端,这里就不一一描述了,总之一点:慎用全局变量

    当然,以上描述的问题(弊端)都是基于项目中存在多个变量的情况,如果项目只有1、2个全局变量,这种不在本文讨论范围之内。

    信号量、队列通信原理

    大部分RTOS的信号量、队列都是使用指针、结构体、数组等,结合系统进行“封装”,使任务间通信更加有效、安全,同时也遵循“高内聚低耦合”的原则。

    比如ucos的信号量post:

    1. INT8U OSSemPost (OS_EVENT *pevent)
    2. {
    3. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
    4. OS_CPU_SR cpu_sr = 0u;
    5. #endif
    6. #if OS_ARG_CHK_EN > 0u
    7. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
    8. return (OS_ERR_PEVENT_NULL);
    9. }
    10. #endif
    11. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
    12. return (OS_ERR_EVENT_TYPE);
    13. }
    14. OS_ENTER_CRITICAL();
    15. if (pevent->OSEventGrp != 0u) { /* See if any task waiting for semaphore */
    16. /* Ready HPT waiting on event */
    17. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
    18. OS_EXIT_CRITICAL();
    19. OS_Sched(); /* Find HPT ready to run */
    20. return (OS_ERR_NONE);
    21. }
    22. if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow */
    23. pevent->OSEventCnt++; /* Increment semaphore count to register event */
    24. OS_EXIT_CRITICAL();
    25. return (OS_ERR_NONE);
    26. }
    27. OS_EXIT_CRITICAL(); /* Semaphore value has reached its maximum */
    28. return (OS_ERR_SEM_OVF);
    29. }

    我们需要传递的有效信息虽然只有一个变量,但它会做“临界区”管理,以及预判一些错误的情况等。

    最后,RTOS源码也可以算是一个优秀的项目,特别是目前普及率比较高、装机量比较多的RTOS,比如µC/OS、FreeRTOS、RT-Thread、ThreadX等。

    最最后,有时间的小伙伴可以阅读一下RTOS源码,RTOS内核我推荐µC/OS,阅读源码能让你掌握一些软件架构的知识,也能让你明白一些开发过程种常见的问题。

    ------------ END ------------

    f30e276be42571a182e7fa8c47a343f1.gif

    ●专栏《嵌入式工具

    ●专栏《嵌入式开发》

    ●专栏《Keil教程》

    ●嵌入式专栏精选教程

    关注公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。

    ec965578e74ca4b6abf96c0b541e6635.jpeg

    b702c9555e4b2306834b8b940cb24103.png

    点击“阅读原文”查看更多分享。

  • 相关阅读:
    css样式:禁用文字选中状态,禁止图片拖动
    MySQL8.0-分组函数ROLLUP的基本用法(GROUPING)
    mybatis中有哪些执行器(Executor)呢?
    创信短信API的无代码开发集成:电商平台、CRM和用户运营
    Redis高可用实战之Replication
    8月19日PMP出成绩时间公布了!查询攻略请收好!
    Python:实现merge sort归并排序算法(附完整源码)
    【leetcode】【剑指offer Ⅱ】070. 排序数组中只出现一次的数字
    springboot+avue框架开发的医院绩效考核系统全套源码
    性能测试之cpu 分析
  • 原文地址:https://blog.csdn.net/ybhuangfugui/article/details/126357314