Embedded Studio轻松解决C++陷阱:避免在中断时进行内存分配导致的崩溃
来源:segger.com | 作者:风标电子工程师 | 发布时间: 2024-04-12 | 178 次浏览 | 分享到:

现代的C++编程在很大程度上将对底层CPU实际执行的二进制代码的需求抽象化了。然而,这种抽象化在嵌入式系统中可能会导致稳定性问题,而许多开发人员并不一定意识到这个问题的严重性。本文旨在提供一些背景信息,解释这一问题,并提出一些解决方案。










一、背景










在早期,嵌入式设备的程序是用汇编语言编写的。尽管这种方法提供了对底层硬件的精细控制,但它繁琐、容易出错,并且高度依赖于目标CPU的架构。随着嵌入式系统中C编译器的普及,开发人员迅速转向了更高级的语言。

然而,放弃对底层机器的控制权是有代价的。程序员与底层机器和目标系统之间的距离变得更远,对编译器如何将源代码转换为执行指令的过程的控制也减少了。

内存分配和堆栈管理是一个重要的问题。在C程序中,应用程序员可以清楚地知道自己是否、在哪里以及如何使用堆栈。然而,在嵌入式系统中,中断服务例程(ISR)是系统的一部分,这就引入了潜在的问题。










二、问题













中断服务例程中断了正常的程序执行。如果ISR中执行了堆栈操作,而同时该堆栈操作又被中断,就可能导致系统不稳定。例如,同一块内存块可能会被分配两次,一次分配给请求它的ISR,另一次分配给请求它的正常程序。这种冲突会导致不可预测的行为,包括系统不稳定和崩溃。

然而,这个问题往往很难在测试阶段发现,因为它往往是随机发生的,且发生频率较低。这意味着即使存在问题,也很难重现,从而使得问题在最终产品中出现,导致系统的不稳定性。










三、解决方案













一旦问题的根源被确定,解决方案通常就变得更加明确了。以下是两种可能的解决方法:

1、较困难的方法是确保应用程序不会在中断服务例程中调用堆栈相关的函数。

这意味着在ISR中应仅使用C,并且要确保不调用alloc()或free()等可能触发堆栈操作的函数。然而,这并不容易实现,因为ISR可能会调用其他函数,这些函数也必须保证是"无堆栈"调用的。此外,即使您的代码能够满足这一要求,其他团队成员引入的C++代码可能会再次引发问题。因此,这种方法的实施较为困难。如果您决定采用这种方法,一个建议是,在调试构建中,通过在"Lock"例程中添加代码段来检查CPU的中断状态,从而确保内存管理例程不会从中断上下文(ISR)中调用。这样一来,如果存在问题,就可以在开发过程中发现并解决,而不会将问题带入最终产品中。

2、简单方法:在堆栈操作的关键部分禁用中断。

在embedded studio中,这是默认行为,也就是说,在使用embedded studio进行开发时,这个问题就不存在了,它只是简单地在运行!

此外,embedded studio还提供了另一种锁定选项,名为“User”。

在这种情况下,用户可以控制堆栈锁定,以调整系统以适应多核CPU等应用程序。通过使用“User”选项,用户可以根据特定需求对堆栈操作进行定制,以实现更高级别的性能优化和系统调整。这种灵活性的使用可以根据具体的应用场景和硬件配置来优化堆栈操作,确保系统在多核环境或高度时间关键的情况下能够实现最佳性能。