Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;递减单字节(易失性)数组的元素不是原子的!为什么?(另外:如何在Atmel AVR MCU/Arduino中强制原子性)_C++_Arduino_Interrupt_Atomic_Avr - Fatal编程技术网

C++ C++;递减单字节(易失性)数组的元素不是原子的!为什么?(另外:如何在Atmel AVR MCU/Arduino中强制原子性)

C++ C++;递减单字节(易失性)数组的元素不是原子的!为什么?(另外:如何在Atmel AVR MCU/Arduino中强制原子性),c++,arduino,interrupt,atomic,avr,C++,Arduino,Interrupt,Atomic,Avr,我只是浪费了几天,大约25个小时的工作,因为我试图在一些我不知道的简单事情上调试我的代码 它是在C++中减去一个单字节数组的元素,在AVR ATMEGA328 8位微控制器(ARDUNO)上不是原子操作,需要原子访问保护(即,关闭中断)。这是为什么???另外,在Atmel AVR微控制器上,确保原子访问变量的所有C技术是什么 下面是我所做的一个简单的版本: //global vars: const uint8_t NUM_INPUT_PORTS = 3; volatile uint8_t num

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

它是在C++中减去一个单字节数组的元素,在AVR ATMEGA328 8位微控制器(ARDUNO)上不是原子操作,需要原子访问保护(即,关闭中断)。这是为什么???另外,在Atmel AVR微控制器上,确保原子访问变量的所有C技术是什么

下面是我所做的一个简单的版本:

//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.
  }
}
//全局变量:
常数8个输入端口=3;
易失性uint8_t numElementsInBuf[输入端口数];
ISR(PCINT0\u vect)//输入端口0上的外部引脚更改中断服务例程
{
//在这里做事

对于(Unt8It t i=0;i<p)我对ARDUNO和中断不太了解,因此我可能不回答这里的特定问题,但是在多线程环境中使用<代码>递减和递增-和 ++< /COD>绝不是原子的。此外,<>代码> Value也不意味着C++中的“代码>原子< /代码>().虽然我知道当你为微控制器编程时,
volatile
是有意义的,所以我怀疑我的答案可能不适用于你的情况

如果用三个独立的
volatile uint8\u t
s替换一个
volatile uint8\u t
s数组,是否有效?

指示:

ALU支持寄存器之间或常量与寄存器之间的算术和逻辑运算

它没有提到ALU能够直接在内存位置上运行。因此,为了减小一个值,这意味着处理器必须执行几个操作:

  • 将值加载到寄存器中
  • 递减寄存器
  • 将值存储回去
因此,递减操作不是原子的,除非您做一些特殊的事情使其原子化,例如禁用中断。这种读/修改/写要求可能比不更新内存更常见

<> P>一个操作如何能被原子化的细节是平台依赖的。C和C++标准的新版本对原子操作有明确的支持;我不知道ATmega的工具链是否支持这些新的标准。< /P> < P> OK,“为什么要增加/减少单字节变量而不是原子?”这里的答案很好,和

现在我得到了我的答案,
--
减量和
++
增量操作从来都不是原子的,即使是在字节值上进行的操作(参见上面的答案和),我想确保如何在Atmel AVR微控制器上强制原子性的后续问题也得到了回答,因此这个问题在某种程度上成为一个资源:

以下是我所知道的在Atmel AVR微控制器中强制原子化的所有技术,例如Arduino: 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
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)选项2(不太安全、不推荐的方法,因为如果在ISR内部调用的代码块或库中意外使用此方法,可能会导致您无意中启用嵌套中断):

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
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库中保存的宏,当然在大括号中应用了可变范围)
资料来源:

#包含//(放在代码顶部)
原子块(原子块)
{
//这里是原子访问代码
}
相关的:
  • [我的问答]
  • *****[我的回答]

  • 这就回答了:在这里把它当作一个多线程环境。递增和递减从来都不是原子的。这是我不知道的。在Arduino上,int是2字节,所以在Arduino中,对2个或更多字节的变量的任何操作都不是原子的,这是正确的,volatile不会使它原子化……这就是noInterrupts()和interrupts()在C++中,你有任何关于“代码> -<代码> >和<代码> + +< /COD>不是原子操作的来源吗?我的意思是“代码> uint 8xt < /Cult> s,而不是<代码> int >代码> S.Google没有找到任何可靠的来源,所以我没有链接,但是如果你想要原子增量,你应该要么我们e
    std::atomic
    ,使用锁,或使用相应的平台相关函数,如windows上的InterlockedIncrement。@GabrielStaples它不是原子的原因是为增量生成的汇编代码最终是多条指令。在没有锁机制的情况下执行多条指令本质上是不正确的广告安全。感谢你帮助我理解为什么增加/减少一个字节不是一个原子操作。对于现在想知道如何在Atmel AVR微控制器上强制对变量进行原子访问的读者,我在我的答案底部添加了3种方法,因为我认为这个操作信息是第一个问题的答案逻辑问题,为什么我要问为什么?因为标准是这样说的:一个单一的int或字节自动访问的神话是由英特尔处理器非常宽容的。C++不是。你能指给我一个源吗?我会在很多(最多?)上搜索too.Upjutial/减缩运算。平台不是原子的,因为它们依赖于不同的读/修改/写原语。总之,在C或C++中,易挥发< /代码>与原子化、线程间的同步或类似的事情无关。人们一直认为它是这样的,但它却没有。这与java至少不同,其中<代码>易失性< /代码>确实有读/写。写原子性和线程同步保证(但对于递增/递减等操作仍然没有原子性保证)。
    volatile
    在C/C++中是一个禁用优化的关键字,仅此而已。@hyde,I