当单片机遇上状态机(二) 为什么QP难以入门?

非常抱歉,上次的博客发表完以后,就中断了。不少网友在网上揶揄我。我当然没忘记我的承诺,只是前段时间事情多,耽误了。上次的《QP的入门》一篇,发表在网上后,有个网友的回复给我留下了深刻印象:

qingfeng_ling
这是刚开始给个大体的框架吗,还是已经开始正式讲解了,要是正式讲解的话,我觉得还是有点深了,也可能我太菜[捂脸]
学习者阿曼酱回复qingfeng_ling
你不是一个人[捂脸]

这说明,《QP的入门》一文,写的还是不够浅显明了,有些网友没有成功的由此文入门QP。我用了QP很多年了,尽管我在写博文的时候,很用心的揣摩初学者的心情,但也难免按摩的不到位,还是把一些不必要的概念引入进来。但是,除了上述原因外,我觉得可能还有一些其他的原因,有必要写一下,说清楚,作为《QP入门》一文的补充。

QP涉及到了太多与传统的嵌入式编程思维不同的编程思想。例如,面向对象的C编程,Actor模型,事件总线,发布-订阅模式,设计模式,RTC等等。这些概念,无论是传统的前后台的编程,还是RTOS编程中,都是不曾涉及的概念。QP实际上是将PC上的某些编程技术引入了进来。比如,Actor模型,是Erlang语言内置的并发模型;面向对象的C编程,尽管应用广泛,但对于大部分的嵌入式工程师来说,还是比较陌生;事件总线或者消息总线,在物联网、机器人或者分布式领域,会有所涉及(比如ROS、MQTT和微软的COM编程)。这些概念,都要求QP的学习者,要事先掌握,或者在QP的学习中,同步掌握。如果没有理解这些概念,在QP学习中,会感觉非常困惑,因为它颠覆了你的之前的固有思维。

面向对象的C编程

很多嵌入式工程师,对C语言的理解,还是停留在谭浩强的《C程序设计》一书的水平上,认为C语言是一门面向过程的语言,因此只能写面向过程的程序,如果要写面向对象的程序,只能用C++、Java、C#才行。还有一部分工程师,他们是了解OOPC(面向对象的C编程)的,但思想局限在Lwoopc等面向对象的框架上,注重面向对象的形式,要想C++等语言靠拢,而不注重面向对象的思想。

在这个问题上,我的建议是,看官方文档,看优秀源码(RT-Thread设备框架、STM32标准库)!QP有一份官方的技术文档,《》,就是专门介绍入门OOPC的,完全可以借鉴。另外,有几个源代码,是非常严格的OOPC实现,我最推荐的是RT-Thread的设备框架。为什么是设备框架,而不是它的内核源码?因为面向对象的三大特性,封装、继承和多态,设备框架都有涉及到,而内核代码,仅仅是涉及到了封装与继承。

Actor模型

关于对Actor模型的说明,我推荐两本书《七周七并发模型》和《程序员修炼之道:通向务实的最高境界》(我可不是卖书的,哈哈)。
《七周七并发模型》一书最大的意义在于,它告诉你多任务的本质是什么。并发有多种实现方式,不仅仅是线程与锁模型(多任务)一种。它会将嵌入式工程师们,从【多任务是实现并发的唯一手段】的思想禁锢中解放出来,让你开始关注在计算机和软件发展的历史长河里,出现多很多种并发模型,而线程与锁(多任务)只是非常普通的一种,让你开始意识到协程是怎么回事,线程又是什么,Actor是啥,CSP模型有是啥?
《程序员修炼之道》一书的并发的部分,从另外的角度上,阐述了Actor模型和线程与锁模型,尽管篇幅不大,却非常切中要害。

事件总线

事件总线(Event Bus)、消息总线(Message Bus)和软件总线(Software Bus)的概念,应用不多,资料也不多,很多应用,都是把它集成在软件内部,不对外开放,因此我们不太能感受到。在QP里,对这个概念也仅仅出现在很少量的文档里,一笔带过。如果想深入了解,机器人领域的小伙伴们,肯定都知道ROS,它有一个分布式消息机制,就是一个典型的分布式消息总线;物联网领域的小伙伴,可以用一下MQTT,这也是一个的分布式消息总线;如果大家对鸿蒙操作系统感兴趣,它的系统底层,就有一个分布式软总线。当然,QP的事件总线,并不是分布式的,但它山之石,可以攻玉,对其他类似技术的了解,可以加深对事件总线概念的理解。

设计模式

有很多书和资料,都在介绍设计模式,但大多针对的是C++、Java、C#等可以面向对象的语言。对于嵌入式工程师来说,设计模式的应用是陌生的。我觉得有三大原因:一是设计模式要以面向对象为基础,长期以来嵌入式应用过于简单,没有面向对象的需求,面向过程即可应对;二是嵌入式的代码规模太小,根本不需要使用设计模式来应对需求的变化,三是大家一直在讨论的23种经典设计模式,有不少并不适用于嵌入式软件,而嵌入式中,形成的很多设计模式,相对来说比较简单,没有对主流软件界形成影响。举一个例子,按键去抖动,就是一个典型的嵌入式设计模式,但很多工程师只知道这个“套路”,并没有把它抽象到设计模式的高度。

有几种嵌入式中常见的设计模式以及学习资料,列举在这里:单例模式、工厂模式、命令模式、适配器模式、状态模式、观察者模式、发布-订阅模式、状态模式、去抖动模式、黑板模式、中断模式、轮询模式、队列模式、临界区模式等等。后续会专门讲解《设计模式》。

RTC原则

要想理解RTC原则,需要了解两个前置知识,一是Actor模型对事件是怎么处理的,二是协程。
Actor模型中,每一个Actor一次只能处理一个事件。可能网友问了,难道还能处理多个事件?是的,当一个队列里的事件都在一个线程里处理的时候,它就只能一次处理的一个事件;二当处理一个队列的事件是一个线程池的时候,多个事件同时被分配了多个线程,这时可能会出现同时处理的情况。当一个Actor处理完当前事件,才能进行下一个事件的处理时,不管这个事件处理的过程会不会被其他的Actor打断,这个事件处理过程都是RTC的。RTC有很强的优势,也带来了一些坏处,我们在后续的博客里进行讨论。
当QP框架使用了QV的内核来调度时,每一个Actor作为一个调度单元,就从线程退化为了协程。协程的QP有着独特而有趣的优势,如果你的实时性要求没那么大的话(10ms的误差可以接受),而又完全不设计我非常推荐使用QV内核来进行嵌入式开发。它能让你的程序非常非常稳定可靠,这个问题我们会在后续的博客中进行详细阐述。

总结

综上所述,QP有一定的学习曲线,最关键的是把握QP的前置知识,理解QP的思维。下次博客会直接讲QP的哲学思想。

上一篇:PhysX3.4文档(5) --Rigid Body Collision


下一篇:力扣-367题 有效的完全平方数(C++)- 二分法