两个任务之间的同步

时间:2009-08-03 09:47:23

标签: synchronization embedded firmware

这实际上是嵌入式系统中固件的设计问题 我有两个独立执行的ISR(具有相同的优先级)。 当h / w生成数据时会触发这些ISR。 我想要一个必须在task1和task2之间同步的机制。任务2必须知道在task1中计算的某些值,然后在计算task2中的某些值时必须考虑这些值。 我没有使用OS原语,即系统没有任何操作系统。 Task1在ISR2的上下文中的ISR1和task2的上下文中执行。 我们使用的处理器是STMicroelectronics 32控制器

编辑:其他信息 处理器连接到某些IP,当它们准备好数据时触发中断。这些IP在输入流帧数据上充当累加器类型。

4 个答案:

答案 0 :(得分:4)

我不会在中断上下文中进行繁重的处理,只需读取数据并设置标志。

然后可以在主循环中的简单调度程序中检查标志,以根据需要执行任务。因此,任务不能互相中断,也不能看到其他任务的输出不一致。

任务还可以设置此标志以激活另一个任务。例如。 Task1可以激活Task2,因为Task2需要来自Task1的值。

对于在ISR中读取的数据,您需要一些缓冲区。取决于传入数据的时间,可能是环形缓冲区或双缓冲区。

答案 1 :(得分:2)

  • 在读取或写入共享值
  • 之前禁用中断
  • 读取或写入共享值
  • 后重新启用中断

答案 2 :(得分:2)

我会尝试根据有限的信息给你答案,假设:

  • 一个简单的自制调度程序用于根据简单的criterea调用task1和task2
  • task1和task2运行完成(即不要互相抢占)
  • 数据是基于字节的流(如果需要数据包,则需要稍微不同的实现)

我在设计嵌入式系统时经常尝试的是最大限度地减少信号量的使用,并模拟无锁数据流。我将在下面说明这一点:

asynchronous (lock free) communication queues http://www.freeimagehosting.net/uploads/477741db06.gif 可以通过使用线程安全的FIFO队列将ISR与任务分离。可以在http://msmvps.com/blogs/vandooren/archive/2007/01/05/creating-a-thread-safe-producer-consumer-queue-in-c-without-using-locks.aspx

中找到一个示例

这样的实现(没有锁定)没有操作系统依赖性,应该很容易支持。这也提供了一个明确的生产者 - 消费者设计,没有死锁。

假设任务由home-brewn调度程序触发,您可以选择检查那里的事件(非空fifo)。 即if(TRUE == fifo_filled(my_read_queue)){invoke task 1}

现在关于task1和task2的同步。 如果task1只是生成数据,则可以使用相同的机制:如果你有一个队列(fifo),task1可以在其中写入数据,任务2可以读取,那么任务就会被解耦。同样,这可以在您的调度程序中检查(if(TRUE == fifo_filled(task1_to_2_queue()){invoke task2}}

如果您需要更多(例如,如果任务未运行完成但被抢占),您将需要一些机制来同步。选项包括: - 无论如何使用(免费)操作系统或简单的调度程序 - 酿造你自己的(我的经验:只有当它像for循环和一些if语句一样简单时才应该完成) - 使用简单的调度程序(比完整的RTOS轻得多) - 将task1和task2集成在一起的重构代码。在这种情况下,您将有效地使调度程序成为应用程序代码的一部分。

注意:我在本说明中使用的示例函数(fifo_filled())不是示例代码的一部分。如果(读!=写)它应该返回true 此外,示例代码使用全局变量读写;你可以谷歌一个能够处理多个队列的函数,或者将读/写和缓冲变量移动到结构中,并参考参数中的结构。

另一种方法是通过中断禁用创建一个关键部分。但是,我试图限制它,因为它经常创建一个强大的系统耦合,并且代码变得更难重用。

答案 3 :(得分:2)

我是从没有操作系统,没有C和寄存器等真正的框架的角度来看这个。我这样做的方法是为每个ISR提供一个状态变量,其他ISR可以看到。然后当您输入ISR1时,您只需检查ISR2的任务状态并根据需要进行操作。然后调用ISR2并检查其自身的状态和ISR1的状态,并按其认为合适的方式运行。我在头文件中使用ENUM来枚举状态以便清晰(INIT,WAITONDATA等),然后在ISR中使用一个开关来处理每个状态。然后你必须确保两个ISR都可以看到需要共享的数据并且你已经设置好了。

当然,正如其他人所说,你不想在ISR中做很多计算。您只想设置一个事件已发生的标志或某些数据,然后处理主循环中的数据。然后,您的系统不会被阻止处理ISR太长时间。您可以以相同的方式执行此操作 - 可以在主循环中看到的状态变量(或者至少是您从主循环执行数据操作的函数)和ISR。在ISR中更改其状态并在主循环函数中检查该状态。根据需要做家务。

不要忘记 - 如果要更新ISR中的变量,则必须将它们定义为volatile!

volatile uint8 state = INIT;

例如。