任务间的互斥、同步、通信
FreeRTOS 是多任务系统,一般会创建有多个任务,每个任务都是独立的,彼此不会无缘无故的互相干扰,不同的任务之间有时也需要进行一个“沟通”,需要建立起一种依赖关系,一起协调工作的完成。这种“沟通”方式有:互斥、同步、通信。
什么是互斥、同步、通信?
同步:同步,指协调工作的进行,用在多个任务的执行中控制轮到哪个任务执行和什么时候执行。例如,把任务比成班级里的同学,同学 A 和同学 B 一起完成一道数学大题,题被分成两小题,同学 A 做第一小题,同学 B 做第二小题,不过第二小题需要第一小题的计算结果才能继续往下算,所以同学 B 需要一直等待同学 A,只有等同学 A 做完后告诉同学 B 结果,同学 B 才能开始做题。(B 需要 A 的答案才能做题,所以等待的过程中什么都做不了,这个等待过程就被称为阻塞)
互斥:用于保护共享资源,避免数据错误。通过给公共资源上锁,防止不同任务能同时使用同一个公共资源(例如全局变量)。把公共资源和任务分别看成厕所和上厕所的人,则厕所一次只能有一个人使用,每次有人使用就会把厕所门锁上,防止别人进来,使用完再开锁,放给其他人用。
通信:用于任务之间传递数据、事件和消息。是任务之间交换信息和共享数据的过程,让彼此知道发生了什么,传递必要的信息和状态。
同步和互斥区别
同步,是在互斥的基础上,还决定了下一个操作共享资源的任务是谁。例如,有三个人上厕所,分别是A、B、C。A 先上的厕所,上厕所时把门锁上,不让 B、C 进来,在等待过程中 B、C 只能干等着,什么都做不了,这个过程就是阻塞,A 上完厕所后,开门指定 C 先上,让 B 等着,这就是同步。而互斥就不存在 A 上完出来指定 C 先上,而是打开厕所门后,由 B、C 自己去争夺,谁先抢到,厕所就归谁。
任务间的互斥、同步、通信如何实现?
通过队列、信号量、互斥量、事件组、任务通知来实现的。
队列、信号量、...之间的对比
内核对象 | 生产者 | 消费者 | 功能 |
队列 | 谁都可以往队列里放数据 | 谁都可以从队列里读数据(读一个数据队列会少一个数据) | 用来传递数据,每次只能唤醒一个接收者 |
信号量 | 谁都可以增加一个数量 | 谁都可以消耗一个数量 | 用来维持资源的个数,一个资源只能唤醒一个接收者; 我要使用这个东西,没有的话我就先停下手头工作等,等这个东西出现,等到有了这个东西我才继续工作,开始使用这个东西; |
互斥量 | 只能 A 上锁(占用这个资源,不让别人使用) | 只能由 A 开锁(放开资源给别人使用) | 就像使用厕所,谁使用谁就上锁,也只能又他开锁; 我要用这个东西,别人先不准用,等我用完了别人才能用(就类似上厕所,我想要拉屎,需要用到厕所,在用厕所时会把门上锁,防止别人进来,等我用完了开锁别人才能使用) |
事件组 | 谁都可以设置事件标志位(设置事件标志位为1,就代表事件已完成,代表资源已生产完毕) | 谁都可以等待事件标志位(等待生产者完成某事件,好让我进行下一步操作) | 用来传递事件,置1代表完成了事件,在等待事件完成的任务会阻塞,只有事件完成了才会被唤醒。可以唤醒多个接收者 |
任务通知 |
|
|
|
队列、信号量、互斥量、事件组这些都是在内核中创建一个结构体,结构体作为任务间沟通的中介,无论是数据交换还是通知,都是通过这个结构体来实现。
任务通知则是直接发个信号给对方任务的 TCB,不需要中间媒介(任务通知这方面了解的较少)。