【问题标题】:malloc alternative for interrupt safety中断安全的 malloc 替代方案
【发布时间】:2017-08-30 13:20:55
【问题描述】:

再说一次,我不是开发人员而是木工,所以我的问题可能很愚蠢。

我忘记了一些非常重要的事情,我必须使用 gcc-3.8 进行编译,因为我正在使用的原始代码无法使用新版本进行编译。我完全忘了谈这个,抱歉。

我正在将数据从工具发送到自主机器人。 机器人以无符号字符形式接收数据* 我读了很多,似乎 malloc 不是中断安全的。

由于机器人可能会做坏事和危险的事情,我会尽量确保每个部件的安全(至少尽可能)。

这个 malloc 发生在接收到的数据引发中断之后。 这个代码段现在让我很难让它安全,而且我的语法可能很糟糕..

char* _Xp = (char*) malloc(strlen((char*)_X)*sizeof(char));
strcpy(_Xp, (char*)_X);

1) malloc 真的不安全中断吗?我找到的信息是 2004 年的。

2) 有没有更有效的方法来初始化缓冲区?

3) 为什么 unsigned char “坏”? (阅读相关内容)。

4) 最后一个问题是 strcpy 也不安全中断吗?我读到的资料在这一点上有所不同。

===== 回答一些问题:

机器人没有操作系统,目标是 25Mhz 的 STR911FFM44(如果有帮助的话)

输入数组都是以 nul 结尾的。

代码不在中断处理程序中,而是在无限循环中,并且仅当 IrHandler 为其设置标志时才进行处理。

我不知道数据流对安全性“硬编码”的速率。但中断应该在 [500ms 到 1500ms] 内。

【问题讨论】:

  • 我想你不知道_X 是否是nul-terminated,是吗?另外,malloc 的返回也不需要强制转换,没有必要。有关详细说明,请参阅:Do I cast the result of malloc?。
  • (1) 您的信息是准确的——malloc() 是最不安全的例程之一。 (2) 不要在中断处理程序中进行内存分配。在您的主循环中,发现发生了中断,因此有数据要读取,然后分配缓冲区并读取数据。 (3) 如果您需要使用unsigned char,则没有特别的理由避免使用它。唯一需要注意的原因是库函数几乎都采用char * 而不是unsigned char *,因此使用unsigned char 会使事情变得冗长。
  • 您有两个明智的选择,但它们都归结为在中断处理程序中做的工作更少。首先,您可以为中断处理程序设置一个缓冲区,并使用单独的代码来填充中断处理程序的缓冲区供应。其次,您可以让中断处理程序只告诉其他非中断代码来处理需要处理的任何内容。本质上,在中断处理程序中做的越少越好,而且你绝对不需要在其中分配内存,因为这可以随时完成。
  • 没有愚蠢的问题。你是一名木工与你的帖子质量无关,主要是因为你做的研究比今天的新手“专业”程序员平均做的多。
  • 你可以通过说“唯一愚蠢的问题是那些没有被问到的问题”来稍微限定一下。 :) 如果@A.albin 将第一段代码写到auto-square my Beismeir Fence System,我将是第一个使用它的人......

标签: c embedded microcontroller interrupt


【解决方案1】:

1) malloc 真的不安全中断吗?

malloc 访问和修改一个全局资源,即你运行程序的公共内存池。如果访问发生在两个不同步的地方,例如您的正常程序流和 ISR1,那么它可能会弄乱池。如果您的 ISR 不调用 malloc 本身,那将不是问题。

如果是这样,您需要建立一个系统来防止此类重新进入malloc。例如,将对malloc 的调用包装在一个关闭中断处理然后再打开的函数中。

2) 有没有更有效的方法来初始化缓冲区?

如果您需要一个具有分配存储持续时间的缓冲区(即您决定它的生命周期何时结束,而不是它分配的范围),那么实际上没有标准的 C 替代方案。顺便说一句,sizeof(char) 始终为 1,因此无需指定。 And since C allows implicit conversion of pointer types from void*,电话至少可以美化一点2:

char* _Xp = malloc(strlen((char*)_X));

3) 为什么 unsigned char “不好”?

它们还不错。实际上,当您需要确切知道字符类型是否有符号时,您必须使用signed char 或unsigned char。普通的char 可以在一个平台上签名并在另一个平台上取消签名。


1 中断服务程序。
2 C 有reserved identifiers 的概念。特别是,任何以下划线开头后跟大写字母的标识符始终是保留的。因此,重命名变量可能有助于提高可移植性。

【讨论】:

  • 好的,明白会更新我的变量名,即使我是唯一使用它的人。
  • @A.albin - 这不是为了保护其他人。标识符是保留的,因为有时语言会用新的关键字更新(例如,在 1999 年添加了 _Bool,在 2011 年添加了 _Noreturn)。使用较新的编译器时出现代码中断是一种耻辱。
  • 我必须用 gcc 3.8 编译(它是一个旧硬件)我想我应该之前说过......
  • @A.albin 即使您使用的是旧编译器,下划线也意味着代码可能与编译器使用的标识符发生冲突。大多数情况下,这不是问题——我使用这种命名约定维护了许多代码库,并且从未遇到过由此引起的任何错误。但从理论上讲,你可能会不走运并使用与编译器相同的标识符。
【解决方案2】:

首先,您说您使用的是裸机微控制器,所以malloc never makes sense。它不是 PC - 您不会与其他任何人共享您的 RAM。所以 malloc 的所有危险和缺点甚至都没有进入讨论,因为 malloc 对您来说根本没有任何意义。

1) malloc 真的不安全中断吗?我找到的信息来自 2004 年。
4)最后一个问题是strcpy也不安全中断吗?我读到的资料在这一点上有所不同。

在 ISR 和主应用程序之间使用共享资源的函数没有中断安全的。您应该避免从 ISR 调用库函数,它们应该保持最小。

必须小心处理 ISR 和调用者之间共享的所有数据。您必须确保对单个对象进行原子访问。您必须声明volatile 等变量以防止优化器错误。您可能必须使用信号量或其他同步方式。这适用于所有此类数据,无论您是自己更改还是通过库函数更改。

如果不执行上述所有操作,将导致非常神秘和微妙的错误,从而导致数据损坏、竞争条件或永远不会执行的代码。总的来说,由于所有这些额外的复杂性,中断总是很难处理。仅当您的实时要求没有其他选择时才使用它们。

2) 有没有更有效的方法来初始化缓冲区?

是的,使用数组。 static char _Xp [LARGE_ENOUGH_FOR_WORST_CASE]; 通常将此类缓冲区保留在 .data 段而不是堆栈中是个好主意,因此使用了 static 关键字。

3) 为什么 unsigned char “坏”? (阅读相关内容)。

它们本身并没有什么不好。不过,不同的char 类型是有问题的,因为理论上它们可以具有8 位以外的其他大小。更糟糕的是,没有签名/未签名的char 具有实现定义的签名,这意味着它可能是有符号的或取决于编译器。这意味着您应该从不使用char 类型来存储除文本字符串之外的任何其他内容。

如果您需要变量类型来保存数据字节,请始终使用 stdint.h 中的 uint8_t。

由于机器人可能会做坏事和危险的事情,我会尽量确保每个部件的安全(至少尽可能)。

为嵌入式系统编写安全软件是一项高素质的任务。我不建议任何全职从事嵌入式固件编程工作经验不足 5 年的人考虑它,除非您的团队中至少有一名经验丰富的 C 资深人士,并且所有代码都通过了同行评审和静态分析.

听起来您将从阅读 MISRA-C:2012 编码指南中受益匪浅。它是 C 语言的一个安全子集,旨在用于安全关键型应用程序或任何有缺陷的应用程序形式。不幸的是,MISRA-C 文档不是免费的,但它正在成为行业标准。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多