2017-05-04 34 views
0

我需要在我的代码中进行数据同步。 目前我正在访问中断内部的全局值,并且在本地函数中,如果中断调用频繁可能会破坏数据。我需要避免这种情况。我没有在我的代码中使用操作系统,所以我不能使用信号量。使用与信号量类似的锁定方法可能会解决我的问题。不使用semapore中的数据同步C

任何帮助,将不胜感激

+1

发布您的代码。 –

+1

告诉我们关于您的硬件环境的一些信息。如果你有一个CPU核心和一个执行线程,最简单的方法就是在你进行更新时禁用中断。在多处理器环境中,处理器指令集通常会进行原子测试和设置指令或等效。 – JeremyP

回答

4

中断比线程或进程的工作方式不同 - 如果一个线程等待一个信号,它根本就没有或计划,直到信号灯变得可用,如果给定的等待超时时间。同时,可以安排其他线程,其中一个线程可能会回馈信号量。

中断服务程序并不是这样 - 它们不会被任何线程调度(如果有的话,只有其他中断)中断,而是被执行直到它们返回。所以如果一个ISR等待一个信号量(或者类似的机制,正如你所要求的那样),那么我们就处于一个死锁状态,因为持有它的线程不能再被安排来给信号量返回......

所以你需要一个完全不同的机制!

通常的做法是禁用中断,只要你的函数需要访问公共数据,然后重新启用它(你也可能需要在ISR本身内部完成)。

怎么样?那么,操作系统/硬件的具体 - 只要你不提供进一步的细节,我在这里...

只是一些提示呢:保持禁用中断的时间尽可能短,并确保通常访问的数据被声明为volatile!

+1

无锁数据结构也可以提供帮助! – unwind

+0

您不必等待永久循环来获取信号量,也可以检查它是否可用。否则,ISR将不得不丢弃该值或将其保存在缓冲区中。 – Lundin

1

这也可能是因为这在主代码一样简单:

disable_interrupts(); 
value += 1; 
enable_interrupts(); 

所以你要确保当你在主代码使用值中断不能点火。

+1

如果这些函数改变了全局中断掩码,那么这不是一个好主意。理想情况下,您应该只禁用受影响的中断。 – Lundin

+0

@Lundin问题中没有足够的信息来提供理想的答案。 –

+0

这个代码可以禁用全局中断掩码,或者它不会 - 它不明确,并且与问题无关。在我使用过的几个系统中,一个名为'enable_interrupts()'的宏导致设置/清除全局中断掩码。除非您完全控制MCU中的所有中断,否则这通常不是一个好主意。 – Lundin

1

你需要的是对数据的原子访问。如果它是一个单一的变量,你可以保证访问是原子的,那就足够了。但是,这涉及到反汇编C代码,并看看你最终结果如何。即使机器代码以原子(单指令)结尾,它也不可移植。

如果你有一个支持C11的现代编译器,你可以声明共享变量为_Atomic,这将解决这个问题。

另一种选择是在调用者的变量访问期间简单地关闭特定的中断。然而,这会干扰实时性能,并且可能会漏掉中断。

通用的“最佳”解决方案可能是自己发明一个信号量。例如:

// volatile to prevent dangerous compiler optimizations; does not solve re-entrancy 
volatile uint32_t data; 
volatile bool guard; 

void ISR (void) 
{ 
    if(!guard) 
    { 
    data = SOME_REGISTER; 
    } 
} 

void main (void) 
{ 
    ... 
    guard = true; 
    uint32_t local = data; 
    guard = false; 
} 

在上述例子中没有原子访问在所有保证,即使不将guard变量。但是,它不再是必需的,因为在main()即将读取数据时,保证设置guard。如果在读取期间中断将会启动,它不会破坏数据。

这个解决方案唯一的缺点是当你设置警卫时你将错过更新data。如果这是一个问题,你将不得不实施某种形式的临时存储。 (注意,这段代码并不会导致“内存障碍”,所以在复杂的多核处理器上,这种方法可能不起作用,并且volatile不一定会导致内存障碍。在普通的微控制器上,它将工作得很好虽然)。

+0

上述解决方案很好。我的实际情况是,我将ADC中断的值保存在全局变量中,并将其更新为另一个子函数内的局部变量。所以函数和中断会被频繁地调用;所以我们需要在中断中设置和重置guard变量,并在本地变量尝试访问全局变量之前提供函数检查。当局部变量试图访问全局变量并且中断发生的时间和全局变量的值被更新导致数据损坏时,问题就出现了。 – Navin

+0

@Navin中断不能被调用者中断,所以不需要在那里设置防护。 (除非你有一个多核解决方案,第二个内核执行中断。) – Lundin

+0

@Lundin非常全面的回答覆盖所有的事情想想 –