本质就是一个环形缓冲区,再加上任务的休眠和唤醒。
环形缓冲区+休眠唤醒
队列的结构体:
队列就是:你可以指定这个环形缓冲区里每一个元素多大,有多少个元素。
怎么传递数据?
一个任务写对队列,另外一个任务读队列。
要读数据的时候,先读第1个数据,就是从头部读。
假设读到了一个数据,头、尾就是这样的:
这时候如果我再写一个数据,头和尾就是这样的:
对于队列操作,我们一般来说是往尾部上写数据,
但是你也可以说:我这个数据比较着急处理,我可以写到头部去。
但读数据的时候,永远是从头部读。
队列的结构体,里面有2个链表:
一个是用来管理那些等待空闲以便写入数据的任务,
另一个用来管理那些等待数据以便读出数据的任务。
task2读队列,因为没有数据而休眠,并且会把自己放在队列的这个链表上:xTasksWaitingToReceive。
task1写队列,会去队列的这个链表:xTasksWaitingToReceive,挑出一个任务把它唤醒。
任务的切换,就是把任务放在不同的链表,再来分析task2读队列时:
1.因为没有数据而休眠 ==> 从ready list放到delay list
放入delay list是因为,可能它并不想死等,还给自己规定了超时时间,
时间到了,tick中断要从delay list把它唤醒。
2.并且会把自己放在队列的这个链表上xTasksWaitingToReceive。
即一个任务,想去读队列,但是队列里没有数据,就休眠:会把自己放入两个链表。
我们再来看看任务1,任务2读不到数据就休息了,任务1写数据后发生了什么事?
task1写队列,会去队列的这个链表:xTasksWaitingToReceive,挑出一个任务把它唤醒?
在等待数据的链表xTasksWaitingToReceive,有很多个任务,有的优先级高,有的等待时间长。
谁优先级高唤醒谁,
如果优先级都相同,谁等待时间长,就唤醒谁。
信号量的代码就是队列的代码:
信号量的创建函数:
可见信号量与队列的差别:
在队列里面,需要分配存储数据的空间,
在信号量里面,并不需要分配存储数据的空间,
我们使用队列来传递数据,我们使用信号量并不是用来传递数据。
我们使用信号量时,只关心一个计数值.
左边的生产者,把计数值加1
右边的消费者,把计数值减1
右边的消费者,想去获得产品,但是计数值等于0时,消费者可以阻塞
可以简单的认为:
信号量=全局整数+休眠唤醒
队列=环形缓冲区+休眠唤醒
信号量也有休眠和唤醒,只不过give信号量不成功时,当前任务不会阻塞。
从函数的参数,就可以知道:Give信号量的时候,无需休眠.
Take信号量的时候,可以休眠。
并不需要传递数据,只是传递一个状态,就可以用信号量。
举个例子:
任务A负责WiFi连接,他连接成功之后,就可以发一个信号量。
任务B负责连接服务器,他获得信号量之后,才会去连接服务器。
Ab之间,并不需要传递数据,只需要传递一个事件:这时候就用信号量。