1

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

任何帮助,将不胜感激

4

3 回答 3

4

中断的工作方式与线程或进程不同 - 如果线程等待信号量,则在信号量可用或等待超时过去之前不会对其进行调度。同时,可以调度其他线程,其中一个线程可能会返回信号量。

中断服务例程不是这种情况——它们不会被任何线程调度中断(如果有的话,那么只会被其他中断),但会一直执行到它们返回。因此,如果 ISR 等待信号量(或您要求的类似机制),我们将陷入死锁,因为无法再调度持有它的线程来返回信号量......

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

执行此操作的常用方法是,只要您的函数需要访问公共数据,就禁用中断,然后重新启用它(您也可能需要在 ISR 本身内执行此操作)。

如何?好吧,特定于操作系统/硬件-只要您不提供更多详细信息,我就在这里...

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

于 2017-05-04T10:43:53.380 回答
1

在您的主代码中可能就像这样简单:

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

因此,当您使用主代码中的值时,请确保中断不会触发。

于 2017-05-04T11:11:13.170 回答
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也不一定会导致内存屏障。但在普通微控制器上它可以正常工作。)

于 2017-05-04T13:58:14.343 回答