我试图理解为什么用户必须调用taskYIELD_FROM_ISR()
方法,而为什么它不会在xStreamBufferSendFromISR
方法内部被RTOS自动调用。
我的问题涉及到FreeRTOS手册第369页。
/* A stream buffer that has already been created. */
StreamBufferHandle_t xStreamBuffer;
void vAnInterruptServiceRoutine( void ) {
size_t xBytesSent;
char *pcStringToSend = "String to send";
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Attempt to send the string to the stream buffer. */
xBytesSent = xStreamBufferSendFromISR(xStreamBuffer,(void *) pcStringToSend,strlen( pcStringToSend),&xHigherPriorityTaskWoken);
if(xBytesSent != strlen(pcStringToSend)){
/* There was not enough free space in the stream buffer for the entire string to be written, ut xBytesSent bytes were written. */
}
/*
If xHigherPriorityTaskWoken was set to pdTRUE inside xStreamBufferSendFromISR() then a
task that has a priority above the priority of the currently executing task was unblocked
and a context switch should be performed to ensure the ISR returns to the unblocked task.
In most FreeRTOS ports this is done by simply passing xHigherPriorityTaskWoken into
taskYIELD_FROM_ISR(), which will test the variables value, and perform the context switch
if necessary. Check the documentation for the port in use for port specific instructions.
*/
taskYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
场景理解
前提条件
- 有两个任务
- Task1 (高优先级) 和 Task2 (低优先级)
- Task1 处于阻塞状态,等待流缓冲区输入
- Task2 处于运行状态,并从
vAnInterruptServiceRoutine
中断
ISR 内部
- ISR 方法调用
xStreamBufferSendFromISR()
- 这个调用意味着,Task1 的阻塞状态将变为就绪状态
情形 A 如果 ISR 方法现在返回,调度程序将不会被调用,Task2 将一直运行,直到时间片结束,然后调度程序切换到高优先级的 Task1。
情形 B
如果 ISR 方法最后调用了 taskYIELD_FROM_ISR(xHigherPriorityTaskWoken);
,则调度程序将被调用,在 ISR 返回后,Task1 将代替 Task2 运行。
问题
- 是否正确,即 Task2 将执行到一个时间片段结束,或者还有其他触发任务切换的原因?
- 为什么在调用
xStreamBufferSendFromISR()
时,RTOS 不会自动调用taskYIELD_FROM_ISR()
方法?
taskYIELD_FROM_ISR()
以及使用“FromISR”API会给程序员带来很大的负担。这也导致了API的重复(“常规”和“FromISR()”API)。但最不幸的是,FreeRTOS的这种设计方面打开了一系列可能出错的范围,其中错误的API类型被使用。例如,回调函数经常从ISR上下文中调用。此外,标志xHigherPriorityTaskWoken
需要以某种方式向上传播到调用堆栈。 - Miro SamekconfigAssert()
可以在开发周期的早期发现配置和使用问题,这是一个很大的帮助。 - bamosportYIELD_FROM_ISR()
,为什么“浪费的任务”在中断服务程序之后还会运行一小段时间? - Daniel ChinwastefulTask
会消耗所有可用的CPU时间:void wastefulTask( void* NotUsed) { while(1) { volatile int i, j; i = 10; j = i; i = j; } }
完整示例的代码可以在github上找到。这个例子来自于《Hands on RTOS with Microcontrollers》(https://www.amazon.com/Hands-RTOS-Microcontrollers-Building-real-time/dp/1838826734)。 - bamos