本小节开始介绍怎样在任务之间进行数据通信。

前面介绍了各个任务之间在执行流程上的行为同步,除了同步之外,任务之间或者中断与任务之间还有可能出于某些需要进行通信,例如给对方发消息,报告状态等待。 本小节介绍最简单的通信方案,使用全局数据。

主要内容

所谓使用全局数据通信,就是让多个任务共享全局数据。
如下图所求,两个任务需要通信时,前一任务可将要通信的数据写入到全局数据中,另一任务在需要时再进行读取。
利用全局数据实现数据通信 - 图1
但这里可能需要解决几个问题。

全局数据共享

多个任务在共享全局数据时,如前面章节所介绍的,需要使用一些资源共享的保护方案。
根据前面所介绍的内容,可使用关中断、信号量等机制保护。

数据缓存

全局数据可能需要缓存多次写入的值,否则如果只能写入一份,将会导致前面已写入的值被覆盖。
该缓存机制可以使用一些数据结构,比如环形队列、链表,甚至哪怕最简单的数组。
利用全局数据实现数据通信 - 图2

读写同步

需要加入某种通知或等待机制,来实现任务在读写资源时的同步。
例如,任务在需要读取数据时,先等待,直到另一任务发通知后已经写入有效数据后,再读取。
这种通知,可以使用本章所介绍的各种同步方案来实现。

示例

在课程中,我们演示了一个非常简单的例子。

  1. static int count = 0;
  2. static tSem syncSem;
  3. /**
  4. * 任务的运行代码
  5. * @param param 任务初始运行参数
  6. */
  7. void task1Entry (void *param) {
  8. for (;;) {
  9. count++;
  10. tSemNotify(&syncSem);
  11. task1Flag = 1;
  12. tTaskDelay(1);
  13. task1Flag = 0;
  14. tTaskDelay(1);
  15. }
  16. }
  17. /**
  18. * 任务的运行代码
  19. * @param param 任务初始运行参数
  20. */
  21. void task2Entry (void *param) {
  22. for (;;) {
  23. tSemWait(&syncSem, 0);
  24. xprintf("task2 count:%d", count);
  25. }
  26. }

这个例子中,定义了全局变量count。但是:

  • 没有使用资源保护机制。因这里功能简单,只是一方读写,写入过程中即便出现打断,读取也不会出现问题,所以不需要保护。
  • 由于只是计数,所以即使task1多次写入,计数仍会累加,task2只关心最后一次写入,所以保护一份最终数据即可。
  • 使用了syncSem进行任务之间的同步。

    重点难点

    注意事项

    可能有的同学觉得这个示例较简单,在课程最终章节的综合实例中,可以看到了在实现串口驱动时,采用了一个更为复杂的例子,用循环FIFO+开关中断+计数信号量实现串口收发中断与多个任务通信的例子。
    在这里,请先理解用全局数据进行通信时要处理的几个问题。

    常见问题