队列与信号量

队列:

本质就是一个环形缓冲区,再加上任务的休眠和唤醒。
环形缓冲区+休眠唤醒
队列与信号量_第1张图片
队列的结构体:
队列与信号量_第2张图片
队列就是:你可以指定这个环形缓冲区里每一个元素多大,有多少个元素。

通过队列传递数据、同步任务,实现互斥操作。

数据传输:

怎么传递数据?

一个任务写对队列,另外一个任务读队列。
队列与信号量_第3张图片
要读数据的时候,先读第1个数据,就是从头部读。

假设读到了一个数据,头、尾就是这样的:
队列与信号量_第4张图片
这时候如果我再写一个数据,头和尾就是这样的:
队列与信号量_第5张图片
对于队列操作,我们一般来说是往尾部上写数据,

但是你也可以说:我这个数据比较着急处理,我可以写到头部去。

但读数据的时候,永远是从头部读。

同步任务:

队列的结构体,里面有2个链表:
队列与信号量_第6张图片
一个是用来管理那些等待空闲以便写入数据的任务,

另一个用来管理那些等待数据以便读出数据的任务。

task2读队列,因为没有数据而休眠,并且会把自己放在队列的这个链表上:xTasksWaitingToReceive。

task1写队列,会去队列的这个链表:xTasksWaitingToReceive,挑出一个任务把它唤醒。

任务的切换,就是把任务放在不同的链表,再来分析task2读队列时:

1.因为没有数据而休眠 ==> 从ready list放到delay list

放入delay list是因为,可能它并不想死等,还给自己规定了超时时间,

时间到了,tick中断要从delay list把它唤醒。

2.并且会把自己放在队列的这个链表上xTasksWaitingToReceive。
即一个任务,想去读队列,但是队列里没有数据,就休眠:会把自己放入两个链表。

我们再来看看任务1,任务2读不到数据就休息了,任务1写数据后发生了什么事?

task1写队列,会去队列的这个链表:xTasksWaitingToReceive,挑出一个任务把它唤醒?

在等待数据的链表xTasksWaitingToReceive,有很多个任务,有的优先级高,有的等待时间长。

谁优先级高唤醒谁,

如果优先级都相同,谁等待时间长,就唤醒谁。

信号量

信号量的代码就是队列的代码:
队列与信号量_第7张图片
信号量的创建函数:
队列与信号量_第8张图片
可见信号量与队列的差别:
在队列里面,需要分配存储数据的空间,
在信号量里面,并不需要分配存储数据的空间,
我们使用队列来传递数据,我们使用信号量并不是用来传递数据。
队列与信号量_第9张图片
我们使用信号量时,只关心一个计数值.
队列与信号量_第10张图片
左边的生产者,把计数值加1

右边的消费者,把计数值减1

右边的消费者,想去获得产品,但是计数值等于0时,消费者可以阻塞

可以简单的认为:

信号量=全局整数+休眠唤醒

队列=环形缓冲区+休眠唤醒

信号量也有休眠和唤醒,只不过give信号量不成功时,当前任务不会阻塞。

从函数的参数,就可以知道:Give信号量的时候,无需休眠.
Take信号量的时候,可以休眠。

什么情况用信号量?

并不需要传递数据,只是传递一个状态,就可以用信号量。

举个例子:

任务A负责WiFi连接,他连接成功之后,就可以发一个信号量。

任务B负责连接服务器,他获得信号量之后,才会去连接服务器。

Ab之间,并不需要传递数据,只需要传递一个事件:这时候就用信号量。

你可能感兴趣的:(Freertos,arm开发)