假设我有function 1
和isr routine
,它们共享并更新相同的标志,它们之间没有任何锁定。 系统是单线程的。
while将是一个3臂程序集指令,这意味着它不是原子操作,是否可以在非isr和isr函数之间共享一个全局变量而没有任何锁定或保护?
功能1:
while (flag == false);
flag = false;
isr例程:
do something
flag=true
我不记得有一个用于在可睡眠和非可睡眠环境之间进行锁定的Linux内核机制,例如: irq
和kernel thread
。
感谢@artless在这里回答了一些我不确定的问题:
有没有办法让我不会错过中断?
内存障碍如何解决问题,代码在单个cpu上运行时是否有效?
在不同情境之间使用障碍时的预期行为是什么?
在loop
期间睡眠可以解决同步问题吗?
答案 0 :(得分:10)
经常引用volatile
作为解决方案,但事实并非如此。它通常会掩盖问题,因为volatile
将始终使代码变慢。如果您的唯一用途如图所示,那么volatile
可能会有效。
使用单个阅读器和单个写来使用memory barriers可能会更好。那将是你的代码,
<强>干线:强>
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 */
此处, barrier 仅强制编译器在此时执行 ARM str
指令。优化器不会在之前或之后移动任何代码。您还可以使用swp
或ldrex
和strex
,具体取决于您的 ARM CPU。同样,环形缓冲区通常与 ISR 和 mainlines 一起使用,因为它们不需要任何特殊的CPU支持;只有编译器内存屏障。
请参阅lock-free并专门搜索lock-free and arm。
修改:有关添加内容,
有没有办法让我不会错过中断?
这取决于中断源。如果它是一个计时器并且您知道计时器源永远不会比 XX 指令快,并且系统中没有其他中断处于活动状态,那么您当前的代码将起作用。但是,如果中断来自外部源,如以太网控制器,非去抖键盘等,可能会很快出现多个中断。有时在中断处理程序期间甚至会发生新的中断。根据ISR来源,有不同的解决方案。 环形缓冲区通常用于对主线的 ISR 中的工作项进行排队。对于 UART ,环可能包含实际的字符数据。它可能是一个指针列表等。当通信变得更加复杂时,很难同步主线中的 ISR ;所以我认为答案取决于中断源。这就是为什么每个 OS 都有这么多原语和基础结构来解决这个问题。
内存障碍如何解决问题,当代码在单个cpu上运行时它是否有效?
内存障碍并不能完全解决错过的中断问题;就像volatile
没有。他们只是让窗口小得多。它们强制编译器提前计划加载或存储。例如主线循环,
1: ldr r0, [r1]
cmp r0, #0 ; xxx
bne 1b ; xxx
mov r0,#1 ; xxx
str r0, [r1]
如果在 xxx 行期间发生第二次中断,则应将flag
设置为两次并错过一次中断。 障碍只是确保编译器将ldr
和str
放在一起。
在不同情境之间使用障碍时的预期行为是什么?
编译器内存屏障我展示的只是让编译器做东西更快。它在上下文之间没有影响。有不同的障碍;但主要是用于多CPU设计。
while循环中的睡眠可以解决同步问题吗?
不是,这只是一种更有效的用法。 ARM WFI
指令可以暂时停止 CPU,这样可以节省电量。这通常是 sleep()在ARM上的作用。如果这是一个问题,我认为你需要改变 ISR 和主线之间的沟通。这取决于 ISR 来源。
答案 1 :(得分:0)
如果您可以将旗帜声明为:volatile int flag;
或volatile bool flag;
答案 2 :(得分:0)
这应该有助于防止错过中断。它基于@artless_noise中非常详细的ans
此处,ISR张贴在信号量上(无阻塞呼叫)。添加障碍以确保写入完成。 该线程将与信号量的运行次数相同。
sem = sem_open(argv[optind], flags, perms, 0); // Initialising semaphore to 0
function 1:
while(sem_getvalue(sem) > 0)
{
flag = false;
//Avoiding the barrier if this value isnt needed by ISR
asm volatile ("" : : : "memory"); /* gcc barrier */
//perform action
}
isr routine:
do something
flag=true;
asm volatile ("" : : : "memory"); /* gcc barrier */
sem_post(sem);
答案 3 :(得分:-2)
是。如果它是单线程模型,则不需要锁定。