我需要在我的代码中进行数据同步。 目前我正在访问中断内部的全局值,并且在本地函数中,如果中断调用频繁可能会破坏数据。我需要避免这种情况。我没有在我的代码中使用操作系统,所以我不能使用信号量。使用与信号量类似的锁定方法可能会解决我的问题。不使用semapore中的数据同步C
任何帮助,将不胜感激
我需要在我的代码中进行数据同步。 目前我正在访问中断内部的全局值,并且在本地函数中,如果中断调用频繁可能会破坏数据。我需要避免这种情况。我没有在我的代码中使用操作系统,所以我不能使用信号量。使用与信号量类似的锁定方法可能会解决我的问题。不使用semapore中的数据同步C
任何帮助,将不胜感激
中断比线程或进程的工作方式不同 - 如果一个线程等待一个信号,它根本就没有或计划,直到信号灯变得可用,如果给定的等待超时时间。同时,可以安排其他线程,其中一个线程可能会回馈信号量。
中断服务程序并不是这样 - 它们不会被任何线程调度(如果有的话,只有其他中断)中断,而是被执行直到它们返回。所以如果一个ISR等待一个信号量(或者类似的机制,正如你所要求的那样),那么我们就处于一个死锁状态,因为持有它的线程不能再被安排来给信号量返回......
所以你需要一个完全不同的机制!
通常的做法是禁用中断,只要你的函数需要访问公共数据,然后重新启用它(你也可能需要在ISR本身内部完成)。
怎么样?那么,操作系统/硬件的具体 - 只要你不提供进一步的细节,我在这里...
只是一些提示呢:保持禁用中断的时间尽可能短,并确保通常访问的数据被声明为volatile!
这也可能是因为这在主代码一样简单:
disable_interrupts();
value += 1;
enable_interrupts();
所以你要确保当你在主代码使用值中断不能点火。
你需要的是对数据的原子访问。如果它是一个单一的变量,你可以保证访问是原子的,那就足够了。但是,这涉及到反汇编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
不一定会导致内存障碍。在普通的微控制器上,它将工作得很好虽然)。
发布您的代码。 –
告诉我们关于您的硬件环境的一些信息。如果你有一个CPU核心和一个执行线程,最简单的方法就是在你进行更新时禁用中断。在多处理器环境中,处理器指令集通常会进行原子测试和设置指令或等效。 – JeremyP