C++ 递减单字节(易失性)数组的元素不是原子的!为什么?(另外:我如何在 Atmel AVR mcus/Arduino 中强制原子性) [英] C++ decrementing an element of a single-byte (volatile) array is not atomic! WHY? (Also: how do I force atomicity in Atmel AVR mcus/Arduino)

查看:25
本文介绍了C++ 递减单字节(易失性)数组的元素不是原子的!为什么?(另外:我如何在 Atmel AVR mcus/Arduino 中强制原子性)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是浪费了几天,实际上是大约 25 小时的工作,因为我试图通过一些我不知道的简单事情来调试我的代码.

I just lost days, literally, ~25 hrs of work, due to trying to debug my code over something simple that I didn't know.

事实证明,在 AVR ATmega328 8 位微控制器 (Arduino) 上,在 C++ 中递减单字节数组的元素不是原子操作,并且需要原子访问保护(即关闭中断).为什么是这样???此外,确保原子访问 Atmel AVR 微控制器上的变量的所有 C 技术是什么?

It turns out decrementing an element of a single-byte array in C++, on an AVR ATmega328 8-bit microcontroller (Arduino) is not an atomic operation, and requires atomic access guards (namely, turning off interrupts). Why is this??? Also, what are all of the C techniques to ensure atomic access to variables on an Atmel AVR microcontroller?

这是我所做的简化版:

//global vars:
const uint8_t NUM_INPUT_PORTS = 3;
volatile uint8_t numElementsInBuf[NUM_INPUT_PORTS];

ISR(PCINT0_vect) //external pin change interrupt service routine on input port 0
{
  //do stuff here
  for (uint8_t i=0; i<NUM_INPUT_PORTS; i++)
    numElementsInBuf[i]++;
}

loop()
{
  for (uint8_t i=0; i<NUM_INPUT_PORTS; i++)
  {
    //do stuff here
    numElementsInBuf[i]--; //<--THIS CAUSES ERRORS!!!!! THE COUNTER GETS CORRUPTED.
  }
}

这是很好的循环版本:

loop()
{
  for (uint8_t i=0; i<NUM_INPUT_PORTS; i++)
  {
    //do stuff here
    noInterrupts(); //globally disable interrupts 
    numElementsInBuf[i]--; //now it's ok...30 hrs of debugging....
    interrupts(); //globally re-enable interrupts 
  }
}

注意原子访问保护",即:在递减之前禁用中断,然后在之后重新启用它们.

Notice the "atomic access guards", ie: disabling interrupts before decrementing, then re-enabling them after.

因为我在这里处理的是单个字节,所以我不知道我需要原子访问保护.为什么我需要它们来处理这种情况?这是典型的行为吗?我知道如果这是一个 2 字节值的数组,我会需要它们,但为什么要使用 1 字节值????通常对于 1 字节值,这里不需要原子访问保护...

所以我们知道在 AVR 8 位 mcus 上读取或写入任何单字节变量是一个原子操作,但是 STM32 32 位 mcus 呢?STM32 上哪些变量具有自动原子读写? 答案在这里:哪些变量类型/大小是原子的在 STM32 微控制器上?.

So we know that reading from or writing to any single-byte variable on AVR 8-bit mcus is an atomic operation, but what about STM32 32-bit mcus? Which variables have automatic atomic reads and writes on STM32? The answer is here: Which variable types/sizes are atomic on STM32 microcontrollers?.

推荐答案

好的,为什么递增/递减单字节变量不是原子的?"的答案Ishamael here迈克尔·伯尔在这里.

Ok, the answer to "Why is incrementing/decrementing a single byte variable NOT atomic?" is answered very well here by Ishamael here, and Michael Burr here.

现在我得到了我的答案 -- 递减和 ++ 递增操作永远不会是原子的,即使在字节值上完成时也是如此(请参阅上面的答案和 Nick Gammon 的链接在这里),我想确保如何 do I force atomicity on Atmel AVR 微控制器也得到了回答,所以这个问题在某种程度上成为一种资源:

Now that I got my answer that -- decrement and ++ increment operations are never atomic, even when done on byte values (see answers above and Nick Gammon's link here), I'd like to ensure the follow-up question of how do I force atomicity on Atmel AVR microcontrollers is also answered so this question becomes somewhat of a resource:

1) 选项 1(首选方法):

uint8_t SREG_bak = SREG; //save global interrupt state
noInterrupts(); //disable interrupts (for Arduino only; this is an alias of AVR's "cli()")
//atomic variable-access code here
SREG = SREG_bak; //restore interrupt state

2) 选项 2(不太安全,不推荐的方法,因为如果您不小心在 ISR 内部调用的代码块或库中使用此方法,它可能会导致您无意中启用嵌套中断):

noInterrupts(); //disable interrupts (Arduino only; is an alias to AVR's "cli()" call)
//atomic variable-access code here
interrupts(); //enable interrupts (Arduino only; is an alias to AVR's "sei()" call)

备选方案 2:

cli(); //clear (disable) interrupts flag; noInterrupts() is simply a macro for this
//atomic variable-access code here
sei(); //set (enable) interrupts flag; interrupts() is simply a macro for this

3) 选项 3(本质上与选项 1 相同;只是使用保存在 avr-libc 库中的宏,并且当然在大括号内应用了可变范围)
来源:http://www.nongnu.org/avr-libc/用户手册/group__util__atomic.html

#include <util/atomic.h> //(place at top of code)
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
  //atomic access code here
}

相关:

  1. [我的问答] 哪些变量类型/sizes 在 STM32 微控制器上是原子的吗?
  2. https://stm32f4-discovery.net/2015/06/how-to-properly-enabledisable-interrupts-in-arm-cortex-m/
  3. ***** [我的回答] 哪些 Arduino 支持 ATOMIC_BLOCK?[以及如何在 C 中使用 __attribute__((__cleanup__(func_to_call_when_x_exits_scope))) 和在 C++ 中使用类构造函数和析构函数复制这个概念?]
  1. [My Q&A] Which variable types/sizes are atomic on STM32 microcontrollers?
  2. https://stm32f4-discovery.net/2015/06/how-to-properly-enabledisable-interrupts-in-arm-cortex-m/
  3. ***** [My answer] Which Arduinos support ATOMIC_BLOCK? [and how can I duplicate this concept in C with __attribute__((__cleanup__(func_to_call_when_x_exits_scope))) and in C++ with class constructors and destructors?]

这篇关于C++ 递减单字节(易失性)数组的元素不是原子的!为什么?(另外:我如何在 Atmel AVR mcus/Arduino 中强制原子性)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆