如何保护 isr 和常规函数共享的全局变量? [英] How to protect a global variable shared by isr and regular function?

查看:24
本文介绍了如何保护 isr 和常规函数共享的全局变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有 function 1 和一个 isr 例程,它们共享和更新相同的标志,它们之间没有任何锁定.系统是单线程的.

Let's say I have function 1 and an isr routine, both share and update the same flag without any lock between them. the system is single threaded.

while 将是一个 3 arm 汇编指令,这意味着它不是原子操作,可以在非 isr 和 isr 函数之间共享一个全局变量而没有任何锁定或保护吗?

the while will be a 3 arm assembly instructions, which means it is not atomic operation, is it ok to share a global variable between non isr and isr functions without any lock or protection?

功能 1:

while (flag == false);
flag = false;

isr 例程:

do something
flag=true

<小时>

我不记得有一个 linux 内核机制可以在可休眠和不可休眠的上下文之间进行锁定,例如irq内核线程.

感谢@artless 的回答,这里有一些我不确定的问题:

  1. 有什么办法让我完全不会错过中断吗?

  1. Is there a way I won't miss interrupt at all ?

内存屏障如何解决问题,代码在单cpu上运行有影响吗?

How the memory barriers solve the issue, does it have effect when the code runs on single cpu ?

在不同上下文之间使用屏障时的预期行为是什么?

What is the expected behavior when using barriers between different contexts ?

在while loop 中睡眠可以解决同步问题吗?

Can a sleep in the while loop can solve problems of syncs ?

推荐答案

使用 volatile 经常被引用作为解决方案,但这并不完全正确.它通常会掩盖问题,因为 volatile 总是会使代码变慢.如果您的唯一用途如图所示,那么 volatile 可能会起作用.

Using volatile is often quoted as a solution, but this is not quite true. It will often mask a problem as volatile will always make code slower. If your only use is as shown, then volatile will probably work.

单阅读器单写使用 内存障碍.这将是您的代码,

It is probably better with a single reader and single write to use memory barriers. This would be your code then,

主线:

volatile int *p = &flag;
while (*p == false);   /* You must use volatile if you poll */
flag = false;
asm volatile ("" : : : "memory"); /* gcc barrier */

isr:

/* do something */
flag=true
asm volatile ("" : : : "memory"); /* gcc barrier */

在这里,屏障只是强制编译器在那个时候执行 ARM str 指令.优化器不会在之前或之后移动任何代码.您还可以根据您的 ARM CPU 使用 swpldrexstrex.同样,环形缓冲区通常与ISR主线 一起使用,因为它们不需要任何特殊的 CPU 支持;只有编译器内存屏障.

Here, the barrier just forces the compiler to do the ARM str instruction at that point. The optimizer will not move any code before or after. You can also use swp or ldrex and strex depending on your ARM CPU. As well, ring buffers are often used with ISR and mainlines as they don't need any special CPU support; only the compiler memory barrier.

查看 并专门搜索 lock-freearm.

See the lock-free and specifically search lock-free and arm.

对于添加,

有没有办法让我完全不会错过中断?

Is there a way I won't miss interrupt at all ?

这取决于中断源.如果它是一个计时器,并且您知道计时器源永远不会比XX指令快,并且系统中没有其他活动的中断,那么您当前的代码将可以工作.但是,如果中断来自外部源,例如以太网控制器、非去抖动键盘等.多个中断可能会很快出现.有时甚至在中断处理程序期间会发生新的中断.根据 ISR 源,有不同的解决方案.环形缓冲区通常用于将来自 ISR 的工作项排入主线.对于UART,环可能包含实际字符数据.可能是指针列表等.当通信变得更复杂时,很难从主线同步ISR;所以我相信答案取决于中断源.这就是为什么每个操作系统都有这么多针对这个问题的原语和基础结构.

This is dependent on the interrupt source. If it is a timer and you know the timer source can never be faster than XX instructions and no other interrupts are active in the system, then your current code will work. However, if the interrupt is from an external source like an Ethernet controller, a non-debounced keypad, etc. It is possible for multiple interrupts to come quickly. Some times new interrupts even happen during the interrupt handler. Depending on the ISR source, there are different solutions. A ring buffer is commonly used to queue work items from the ISR for the main line. For a UART, the ring might contain actual character data. It could be a list of pointer, etc. It is difficult to synchronize the ISR from the mainline when the communication becomes more complex; So I believe the answer depends on the interrupt source. This is why every OS has so many primitives and infra-structure for this issue.

内存屏障如何解决问题,代码在单cpu上运行有影响吗?

How the memory barriers solve the issue, does it have effect when the code runs on single cpu ?

内存屏障并不能完全解决错过的中断问题;就像 volatile 不一样.他们只是让窗口变得更小.它们强制编译器提前安排加载或存储.例如主线循环,

Memory barriers don't completely solve the missed interrupt issue; just like volatile doesn't. They just make the window much smaller. They force the compiler to schedule a load or store earlier. For example the main line loop,

  1: ldr r0, [r1]
     cmp r0, #0    ; xxx
     bne 1b        ; xxx
     mov r0,#1     ; xxx
     str r0, [r1]

如果在 xxx 行期间发生第二个中断,那么您的 flag 应该设置两次,并且您错过了一个中断.障碍只是确保编译器将 ldrstr 放在一起.

If a 2nd interrupt happens during the xxx lines, then your flag should be set twice and you missed one interrupt. The barriers just make sure the compiler places the ldr and str close together.

在不同上下文之间使用屏障时的预期行为是什么?

What is the expected behavior when using barriers between different contexts?

我展示的编译器内存屏障只是让编译器做事更快.它在上下文之间没有影响.有不同的障碍;但主要用于多 CPU 设计.

The compiler memory barrier I show just makes the compiler do stuff sooner. It has no effect between contexts. There are different barriers; but mostly they are for multi-CPU designs.

while 循环中的 sleep 可以解决同步问题吗?

Can a sleep in the while loop can solve problems of syncs?

并非如此,这只是一种更有效的使用.ARM WFI 指令可以暂时停止 CPU,从而节省电量.这通常是 sleep() 在 ARM 上所做的.如果这是一个问题,我认为您需要更改 ISR主线 之间的通信.这取决于ISR 来源.

Not really, this is just a more efficient use. The ARM WFI instruction can temporarily stop the CPU and this will save power. That is normally what sleep() does on the ARM. I think you need to change the communication between the ISR and the mainline, if this is an issue. That depends on the ISR source.

这篇关于如何保护 isr 和常规函数共享的全局变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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