在讲队列前,先思考一下这个问题:
下面这个程序,如果用RTOS实现会出问题吗?
c:
int a = 0;
void fun_a(){
a++;
}
void fun_b(){
a++;
}
int main(){
while(1){
fun_a();fun_b();}}
RTOS:
int a = 0;
void fun_a(){
a++;
}
void fun_b(){
a++;
}
int main()
{
creat_Task(fun_a);creat_Task(fun_b);}
对RTOS代码分析:
我们的期望是运行一次fun_a后a++运行1次,运行1次fun_b后a++运行1次,a = 2
fun_a和fun_b的a++:
1)读a: R0寄存器,读RAM的a的地址,得到a的值
2)修改:R0 自加 1
3)写a:R0寄存器,写RAM的a的地址,修改a的值
接下来模拟一下 RTOS运行
t0:
fun_a:
1)R0寄存器,读RAM的a的地址,得到a的值,R0 = 0,
2)此时到下一个tick,保存现场R0 = 0.
t1:
fun_b:
1)读a: R0寄存器,读RAM的a的地址,得到a的值,R0 = 0;
2)修改:R0 自加 1,R0 += 1,R0 = 1;
3)写a:R0寄存器,写RAM的a的地址,修改a的值;a = 1
t2:
fun_a:
1)恢复现场 R0 = 0
2)修改:R0 自加 1 R0 += 1,R0 = 1;
3)写a:R0寄存器,写RAM的a的地址,修改a的值;a = 1
由上面可知,不符合我们的期望,运行结果为 a = 1
根本问题在于,多个任务一起修改没有互斥机制保护数据。
队列提供了解决的方法,使用QueueSend可以将任务的tick中断关闭,实现裸机运行,修改完数据后再打开中断
接下来再举个栗子
void fun_a(){
while(1){
...达成某条件后flag = 1;...}
}
void fun_b(){
...if(flag = 1){
}...
}
如果运行100w次就要判断100w次太过于浪费CPU
void fun_a(){
while(1){
...达成某条件后写队列:{
1)写Data2)唤醒Queue.list里的任务,并将DelayList里的任务放进ReadyList}...}
}
void fun_b(){
...读队列:{
1)有Data,返回做事2)无Data,休眠:a.将该任务放进DelayList链表b.将该任务插入Queue.List队列}...
}
fun_a可以全速运行
fun_b可以不浪费CPU资源
通过链表和队列实现唤醒休眠
环形缓冲区
这里很简单,就直接贴一下韦老师的图了
读队列
a.关中断
b.
有数据:
1)copy数据
2)唤醒Queue.list里的任务,移除Queue.list第一个任务
3)将DelayList里的任务放进ReadyList
无数据:
1.返回ERR
2.休眠:
1)将该任务放进DelayList链表
2)将该任务插入Queue.List队列
写队列
a.关中断
b.
有空间:
1)写数据
2)唤醒Queue.list里的任务,移除Queue.list第一个任务
3)将DelayList里的任务放进ReadyList
无空间:
1.返回ERR
2.休眠:
1)将该任务放进DelayList链表
2)将该任务插入Queue.List队列
超时唤醒
任务休眠,对于休眠的任务,每次tick中断都会累加计数,然后对DelayList的任务检查是否超时,超时则会移到ReadyList