如何在RTOS上全量支持C++11

简介: C语言自诞生以来已被广泛应用于系统和应用开发。

1、概述

1.1、 C++语言的特点

C语言自诞生以来已被广泛应用于系统和应用开发。比如Google的微内核操作系统fuchsia就是用C实现的,ARM的嵌入式操作系统ARMmbed也主要基于C实现。在应用开发方面,C被广泛用于GUI、游戏引擎、图形引擎、浏览器引擎、数据库等的开发。

C++语言的广泛使用,得益于其如下特点:
(1)支持面向对象编程,封装、继承、多态等机制使编程更加高效。
(2)兼容C,支持面向过程编程及驱动开发。
(3)标准库支持丰富的文件和数据结构操作。
(4)性能优异。

1.2、C++在嵌入式RTOS上的应用

随着MCU芯片处理能力的增强,嵌入式设备的图形显示、模式识别、脚本解析等能力不断赋能设备拓展应用边界。同时,随着应用的不断拓展,对嵌入式设备提出了更高的要求。通常,嵌入式系统采用C语言开发,但GUI、AI算法等复杂应用采用C开发,为此在RTOS上支持C语言的需求变得越来越强烈。

有些RTOS封装系统接口为上层应用提供了自定义的C类,但由于这些类不符合C标准,基于这些类开发的应用缺乏可移植性。另一方面,当使用外部开源软件时,需要进行适配,若软件比较复杂,适配工作量比较大,更为灾难性的是,自定义的类由于不够全,往往很难满足上层软件的需要。所以,最可行的方法还是要支持标准C++库。

image.png

本文主要阐述了基于GCC工具链在RTOS上支持C++的两个关键部分:

RTOS上对C++初始化的支持;
RTOS上适配C++库;
说明:本篇文章基于物联网操作系统AliOS Things上C++11实践总结而成,已在智能音箱等场景中应用。

2、C++初始化支持

对C语言而言,只能用常量或常量表达式初始化全局变量,比如不允许调用函数初始化,也不允许用另一个全局变量初始化。也即是说,全局变量的值在编译时就确定了。另外对于全局数组,其长度在编译时也确定了。

编译器将未赋初值的全局变量放在bss段,有初始值的全局变量放在data段(只读数据放到rodata段)。当RTOS启动时,bss段全部清为0,从程序镜像中读取data段的内容并写入到对应data段的内存,这样就完成了所有全局变量的初始化。

引入C++后,有了对象的概念,这个时候RTOS启动过程中的初始化就不再是清内存、拷贝内存那么简单了。对象内部的空间需要调用new分配,比如虚函数表、一些容器的内部存储空间。同时,对象初始化过程中需要调用父类的构造函数。这些都无法在编译时确定。

C处理这个问题的办法是:把所有C源文件中需要在初始化时调用的函数的地址集中放到一个表中,RTOS在初始化时遍历该函数表并调

image.png
RTOS启动时,初始化C++对象的伪代码如下:

for (f = __ctors_start__; f < __ctors_end__; f++) {

    (*f)();

}

3、在RTOS上适配C++库

在RTOS上实现对C的初始化支持后,下载一个芯片厂商提供的工具链,配置一下编译选项,C似乎可以跑起来,但其实存在诸多问题。

芯片厂商提供的要么是基于linux的工具链,要么是基于裸机的工具链(bare-metal)。在RTOS上显然只能选bare-metal工具链。所谓bare-metal,其含义是无操作系统平台,其线程模式为single,即无多线程并发。在这种模式下,不支持C的多线程,比如不支持mutex、thread、condition_variable等类,同时C库内部实现中不考虑多线程互斥。所以这种模式下的工具链用在RTOS上,一方面功能不全,另一方面存在稳定性隐患,尤其在多核平台上多线程并发问题将变得严重。因此,为了真正实现对C++11的全量支持,需针对RTOS进行适配。

3.1、C++库的依赖关系

GCC工具链中集成了一个C++库,其依赖关系如下:
image.png

上图中三个依赖部分说明如下:

C把C库中的符号导入到std命名空间提供给上层应用使用,同时C内部机制的实现也有赖于C库,比如输出流依赖于puts、putchar等接口。当然,C库也要实现多线程支持,这个有机会另外开辟一篇进行阐述,这里就不展开了。
libgcc库提供了一些较底层的接口与机制,比如C++的线程变量基于libgcc库提供的线程变量管理机制。
C适配层实现了C与RTOS的对接,这部分因底层OS的不同而不同。所以,ARM等芯片厂商或编译器厂商提供的针对嵌入式的工具链往往是裸机平台的,因为RTOS数量众多,无法一一满足。针对特定RTOS的多线程版本工具链需RTOS厂商自己定制。

3.2、适配

适配主要涉及类型与接口两部分,具体可参考./gcc/libgcc/gthr.h文件。

3.2.1、适配的接口说明如下:

image.png

3.2.2、适配的接口如下
image.png

3.2.3、适配说明

用typedef把C内部类型定义为RTOS的类型,基于RTOS的接口实现上述适配接口,便完成了C库的适配。如果RTOS上已经完成了对posix接口的支持,那么适配就比较方便了。示例如下:

//__gthread_t类型定义

typedef pthread_t __gthread_t;



//__gthread_create接口实现

static inline int

__gthread_create (__gthread_t *__threadid,  void *(*__func) (void*), void *__args)

{
    return pthread_create (__threadid, NULL, __func, __args);
}

3.3、配置与重编C++库

在编译C++库时,需配置为使能多线程模式,主要配置项如下:
--enable-threads=posix

其实使能该选项只是触发了配置脚本检查是否支持多线程,若配置脚本执行过程中判断系统不支持多线程,最终编译出来的库还是单线程的。比如,配置脚本中对__GTHREADS_CXX0X宏是否定义进行了判断,若该宏未定义则使能多线程失败。

完成适配与配置后,重编工具链即可生成多线程版本的C库。编译完成后可查看cconfig.h文件,确认使能的C++特性。以_GLIBCXX_USE_SCHED_YIELD宏为例,若没有生成该宏,那么thread类yield()函数实现为空函数、

4、后记

得益于C++良好的封装机制,用C++写的代码比用C写的代码bug率低很多。但硬币的另一面是,调试难度增加了。

即便开启了编译优化,C语言的一行语句与汇编的对应关系也相对比较清楚。但C++由于其复杂的机制,一行简单的赋值语句往往会对应十几条、甚至几十条汇编。这需要RTOS的维测能力提供高效的调试支持。

相关文章
|
存储 Android开发 开发者
Android平台GB28181设备接入端实现实时快照
Android平台GB28181设计开发的时候,有个功能必不可少的:实时快照,特别是用于执法记录仪等场景下,用于图像留底或分析等考量。
|
Web App开发 弹性计算 编解码
最佳实践:如何扩展你的SRS并发能力?
当我们用SRS快速搭建了视频服务,业务也开始上线运行了,很快就会遇到一个问题:如何支持更多的人观看?如何支持更多的人推流?这本质上就是系统的水平扩展能力,SRS当然是支持的,而且有多种扩展的方法,这篇文章就就详细分析各种扩展的方案,以及各种方案的应用场景和优缺点。
2463 0
最佳实践:如何扩展你的SRS并发能力?
|
2月前
|
编解码 开发工具 Android开发
Android平台GB28181设备接入侧如何实现GB28181-2022实时快照
GB/T28181-2022标准中明确了快照的具体要求,包括图像抓拍配置命令的发送与接收流程。源设备需向目标设备发送包含传输路径和会话ID等信息的命令,目标设备完成图像传输后,通过IETF RFC 3428中的MESSAGE方法发送图像抓拍传输完成的通知。图像格式推荐使用JPEG,且分辨率应与主码流相同。技术实现上,如使用大牛直播SDK在Android平台上,可通过创建`SnapShotImpl`类并调用`capture()`方法实现快照功能,之后将JPEG格式的快照文件上传至国标平台。
|
3月前
|
SQL 存储 关系型数据库
PolarDB-X 原生无锁变更,比 gh-ost 更快、更稳定
无论是单机数据库还是分布式数据库,无锁变更都是非常重要的能力。PolarDB-X 无锁变更技术能够极大提升数据库在线操作的灵活性与安全性,它允许在不影响业务连续性的情况下,对表结构进行修改,如增加列、变更列类型等,这对于全天候无间断服务的业务方来说是至关重要的。
|
4月前
|
消息中间件 物联网 数据处理
TDengine 数据接入功能支持 Wonderware 了,不需一行代码完成迁移工作
TDengine 3.2.3.0 引入了 Wonderware Historian (AVEVA Historian) 连接器,简化了数据迁移至 TDengine 的过程,增强时序数据管理与分析。此连接器解决了传统实时数据库扩展性问题,提供成本效益高、国产化的替代方案。TDengine 已支持多种数据源集成,如 OPC、Kafka、MQTT等,打造统一数据平台,助力企业数字化转型。作为高性能时序数据库,TDengine 提供云原生解决方案,减少系统复杂度,加速业务创新。
46 6
|
3月前
|
分布式计算 DataWorks NoSQL
MaxCompute产品使用合集之数据总线同步到DataWorks的任务状态持续显示为HANG(挂起)且同步延迟不断增加,该如何排查
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
5月前
|
消息中间件 Kafka 数据库
实时计算 Flink版产品使用合集之ticdc可以控制全量同步的速率吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
存储 NoSQL Redis
高性能存储 SIG 月度动态:多项内核特性移植到 6.6,erofs 完成共享特性 POC
高性能存储 SIG 月度动态送达,一键了解各项目当前进展。
|
10月前
|
NoSQL Cloud Native Redis
【性能优化下】组织结构同步优化二,全量同步/增量同步,断点续传实现方式
【性能优化下】组织结构同步优化二,全量同步/增量同步,断点续传实现方式
下一篇
无影云桌面