野火RTOS 文档部分的学习
在FreeRTOS,系统调度, 最终也是产生PendSV中断,在PendSV Handler里面实现任务的切换,所以还是可以归结为中断。 既然这样,FreeRTOS对临界段的保护最终还是回到对中断的开和关的控制。
-
关于sysTick 滴答定时器,和PendSV (可挂起的系统调用) 中断
系统有256个中断,在 0-15 的区间是系统内核异常中断,剩下的是外部中断
case1: 需要进行任务切换时,如果SysTick 中断在最高,让它执行中断服务函数就会导致RTOS 系统的时钟出问题。
case2:如果PendSV 优先级最高,中断来时,如果系统正在打开uart 串口,打开到一半去执行PendSV 的中断服务函数了(不会影响rtos 时钟),执行完函数 系统内核的指针就指向下一个步骤 ,就跳过uart
default:总结:设置Systick 中断优先级最高,PendSV 优先级最低,让Systick 中断服务函数触发PendSV 中断。这样又能保证PendSV 中断服务函数在系统初始化结束之后执行,又能保证Systick 一定会触发该中断且不影响系统时钟。
- chatgpt 回复
-
任务管理:
- 中断服务函数
- 任务
- 空闲任务
- 任务执行时间
-
消息队列
-
中断 和信号量
系统中断:
- 硬件或操作系统通过中断机制通知事件的发生,如定时器到期、设备准备好等。
- 中断通常由硬件设备或操作系统内核触发,是异步的,即事件发生时会立即中断正在执行的程序。
- 中断通常用于处理实时性要求高的事件,例如实时数据采集、设备响应等。
- 中断处理程序通常是短暂的,用于快速响应和处理事件。
信号量:
- 信号量是一种同步机制,用于控制对共享资源的访问。
- 信号量通常由软件线程之间使用,用于实现互斥、同步和资源管理等。
- 信号量提供了对临界区的保护,确保同一时间只有一个线程可以访问共享资源。
- 信号量可以用于解决并发编程中的竞争条件、死锁和资源争用等问题。
虽然系统中断可以用于通知事件的发生,但它并不提供同步和互斥的能力。信号量用于线程间的同步和资源管理,确保多个线程在访问共享资源时的正确性和互斥性。
在实际应用中,系统中断和信号量经常一起使用。例如,在一个多线程的嵌入式系统中,中断可以触发某些事件的处理程序,而处理程序在访问共享资源之前可能需要获取相应的信号量来确保资源的正确使用。
综上所述,系统中断和信号量是不同的机制,各自有其适用的场景和目的。系统中断用于异步事件的通知,而信号量用于线程间的同步和资源管理。
-
互斥量
互斥量是一种特殊的二值信号量,更多的是用于保护资源,作为锁的特点。互斥量不能在中断服务函数中使用,因为其特有的优先级继承机制只在任务起作用,在中断的上下文环境毫无意义。
-
用于互锁的互斥量可以充当保护资源的令牌
-
明确一个定义 : 优先级翻转
正常情况下,设备资源被保护了, 当L 在执行任务时,H想要使用该资源,但是由于保护的问题,L不会释放资源,H就被阻塞, 当L还没执行完时,M任务想执行,但是M被L阻塞,当L执行完,M就会先执行M ,然后再执行L。 这就是优先级翻转。
图1(1):L任务正在使用某临界资源, H任务被唤醒,执行H任务。但L任务并未执行完毕,此时临界资源还未释放。
图1(2):这个时刻H任务也要对该临界资源进行访问,但 L任务还未释放资源,由于保护机制,H任务进入阻塞态, L任务得以继续运行,此时已经发生了优先级翻转现象。
图1(3):某个时刻M任务被唤醒,由于M任务的优先级高于L任务, M任务抢占了CPU的使用权,M任务开始运行, 此时L任务尚未执行完,临界资源还没被释放。
图1(4):M任务运行结束,归还CPU使用权,L任务继续运行。
图1(5):L任务运行结束,释放临界资源,H任务得以对资源进行访问,H任务开始运行。
优先级继承: 在H任务申请该资源的时候,由于申请不到资源会进入阻塞态, 那么系统就会把当前正在使用资源的L任务的优先级临时提高到与H任务优先级相同,此时M任务被唤醒了, 因为它的优先级比H任务低,所以无法打断L任务,因为此时L任务的优先级被临时提升到H,所以当L任务使用完该资源了, 进行释放,那么此时H任务优先级最高,将接着抢占CPU的使用权, H任务的阻塞时间仅仅是L任务的执行时间, 此时的优先级的危害降到了最低,看!这就是优先级继承的优势。
图2(1):L任务正在使用某临界资源,L任务正在使用某临界资源, H任务被唤醒,执行H任务。 但L任务并未执行完毕,此时临界资源还未释放。
图2(2):某一时刻H任务也要对该资源进行访问,由于保护机制,H任务进入阻塞态。 此时发生优先级继承,系统将L任务的优先级暂时提升到与H任务优先级相同,L任务继续执行。
图2(3):在某一时刻M任务被唤醒,由于此时M任务的优先级暂时低于L任务,所以M任务仅在就绪态,而无法获得CPU使用权。
图2(4):L任务运行完毕,H任务获得对资源的访问权,H任务从阻塞态变成运行态,此时L任务的优先级会变回原来的优先级。
图2(5):当H任务运行完毕,M任务得到CPU使用权,开始执行。
图2(6):系统正常运行,按照设定好的优先级运行。(将危害降低至最小)
TIP:FreeRTOS的优先级继承机制不能解决优先级反转,只能将这种情况的影响降低到最小, 硬实时系统在一开始设计时就要避免优先级反转发生。
我的理解就是,互斥量是一个含有
优先级继承
的二值信号量。用互斥量处理不同任务对临界资源的同步访问时,任务想要获得互斥量才能进行资源访问, 如果一旦有任务成功获得了互斥量,则互斥量立即变为闭锁状态,此时其他任务会因为获取不到互斥量而不能访问这个资源, 任务会根据用户自定义的等待时间进行等待,直到互斥量被持有的任务释放后,其他任务才能获取互斥量从而得以访问该临界资源, 此时互斥量再次上锁,如此一来就可以确保每个时刻只有一个任务正在访问这个临界资源,保证了临界资源操作的安全性。
-
-
事件
无数据传输,但可以用于 任务与任务间 、 中断与任务间的同步。
对于需要判断某硬件(或其它)处于什么状态,可以使用 全局变量定义一个标志位( 就像MN316 项目中的判断设备是否数据成功上报 或者 设备初始化联网是否成功 ),那么问题就来了?
- 如何对全局变量进行保护呢,如何处理多任务同时对它进行访问?
- 如何让内核对事件进行有效管理呢?使用全局变量的话,就需要在任务中轮询查看事件是否发送,这简直就是在浪费CPU资源啊, 还有等待超时机制,使用全局变量的话需要用户自己去实现。
在某些场合,可能需要多个时间发生了才能进行下一步操作,比如一些危险机器的启动,需要检查各项指标, 当指标不达标的时候,无法启动,但是检查各个指标的时候,不能一下子检测完毕啊,所以,需要事件来做统一的等待, 当所有的事件都完成了,那么机器才允许启动,这只是事件的其中一个应用。
实际运用( OpenCPU 的rtos )
EVENT
-
osEventFlagsWait(init_task_flag, EVNT_INIT_FAIL, osFlagsWaitAll, 70000);
当
option
设置为osFlagsWaitAll
时,该函数只要有任意条件 -
ASK: osFlagsWaitAll 和 osFlagsWaitAny 一样要等到阻塞超时才能执行后续的操作,而且它们会清除标志位的信息( 经过测试,感觉这一块是移动移植的时候的问题 )
实际运用中产生的BUG
-
事件标志位的问题
-
lock 持有锁的实时性,应当持有锁的线程放前面,
否则会出现唤醒之后马上进入休眠的情况。
-
task 线程退出之后记得释放资源。
否则所有线程都退出之后,系统跑飞,回调函数中不能引用os 的资源,但是回调函数会一直跑,导致创建的定时器删不掉
-
事件标志位使用的时候,目前我用OpenCPU 的RTOS 只用了osFlagsNoClear 作为阻塞,拿取事件状态我还是使用的Get 方法。 如果直接用osEventFlagsWait( ); 会出现意想不到的惊喜( 惊吓 )
osEventFlagsGet(conet_task_flag)