关键词不能为空

当前您在: 主页 > 英语 >

FreeRTOS进程管理

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-11 15:01
tags:

-

2021年2月11日发(作者:beach怎么读)


freertos


是一个轻量级的


rtos



它目前实现了一个微内核,


并且


port



arm7, avr, pic18, coldfire


等众多处理器上;目前已经在


rtos


的市场上占有不少的份额。它当然不是一个与


vxwo rks


之类的


rtos


竞争的操作系统 ,它的目标在



于低性能小


RAM


的处理器上。整个系统只有


3


个文件,外加 上


port


的和处理器相关的两个文件,实现是很简洁的。





ucosi i


不同,它是


free


的,

< p>
ucosii


不是


free


的,虽然它的代码是公开的。


FreeRTOS


提供的


功能包括:任务管理、时间管理、信号量、消息队列、内存管理。


Fr eeRTOS


内核支持优先


级调度算法,


每个任务可根据重要程度的不同被赋予一定的优先级,


CPU


总是让处于就绪态


的、



优先级最高的 任务先运行。


FreeRT0S


内核同时支持轮换调度算法,系 统允许不同的任


务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先< /p>



级的任务共享


CPU

< br>的使用时间。这一点是和


ucosii


不同的。




另外一点不同是


f reertos


既可以配置为可抢占内核也可以配置为不可抢占内核。

< br>当


FreeRTOS


被设置为可剥夺型内核时,


处于就绪态的高优先级任务能剥夺低优先级任务的


CPU


使用权,


这样可保证系统



满 足实时性的要求;当


FreeRTOS


被设置为不可剥夺型内核 时,处于就绪态的高优先级任务


只有等当前运行任务主动释放


C PU


的使用权后才能获得运行,



< /p>


样可提高


CPU


的运行效率。

< p>



这篇文章是以


freertos v5.0

版本的代码为例子分析下它的任务管理方面的实现。时间关系可


能没有太多时间写的 很详细了。




1.


链表管理




freertos


里面的任务管理,


queue,semaphore


管理等都借助于双向链表,它 定义了个通用的


数据结构








struct


xLIST_ITEM



{




portTickType xItemValue; //


链表节点的数据项,通常用在任务延时,表示



//


一个任务延时的节拍数








volatile struct xLIST_ITEM * pxNext; //


通过这两个成员变量将所有节点





volatile struct xLIST_ITEM * pxPrevious;//


链接成双向链表






void * pvOwner;


//

指向该


item


的所有者,通常是任务控制块









void * pvContainer; //


指向此链表结点所在的链表










};



这个数据结构定义了一个通用 的链表节点;下面的数据结构定义了一个双向链表




typedef struct xLIST



{




volatile unsigned portBASE_TYPE uxNumbe rOfItems;//


表示该链表中节点的数目





volatile xListItem * pxIndex;//


用于遍历链表,指向上次访问的节点









volatile xMiniListItem xListEnd;//


链表尾结点




} xList;





而下面这个数据结构用在


xList


中,只是为了标记一个链表的尾,是一个


marker



struct xMINI_LIST_ITEM



{




portTickType xItemValue;




volatile struct xLIST_ITEM *pxNext;




volatile struct xLIST_ITEM *pxPrevious;



};



typedef struct xMINI_LIST_ITEM xMiniListItem;





对于链表的操作也定义了一系列的函数和宏,在


list.c< /p>


文件中。如初始化个链表,吧一个节


点插入链表等。




初始化链表


:



void vListInitialise( xList *pxList )



{




/* The list structure contains a list item which is used to


mark the




end of the list.


To initialise the list the list end


is inserted




as the only list entry. */




pxList->pxIndex = ( xListItem * ) &(


pxList->xListEnd );






/* The list end value is the highest possible value in the


list to




ensure it remains at the end of the list. */




pxList->alue = portMAX_DELAY;






/* The list end next and previous pointers point to itself


so we know




when the list is empty. */




pxList-> = ( xListItem * ) &(


pxList->xListEnd );




pxList->ious = ( xListItem * ) &(


pxList->xListEnd );






pxList->uxNumberOfItems = 0;



}



把一个节点插入到链表尾部:




void vListInsertEnd( xList *pxList, xListItem *pxNewListItem )



{



volatile xListItem * pxIndex;






/* Insert a new list item into pxList, but rather than sort


the list,




makes the new list item the last item to be removed by a


call to




pvListGetOwnerOfNextEntry.


This means it has to be the


item pointed to by




the pxIndex member. */




pxIndex = pxList->pxIndex;






pxNewListItem->pxNext = pxIndex->pxNext;




pxNewListItem->pxPrevious = pxList->pxIndex;




pxIndex->pxNext->pxPrevious = ( volatile xListItem * )


pxNewListItem;




pxIndex->pxNext = ( volatile xListItem * ) pxNewListItem;




pxList->pxIndex = ( volatile xListItem * ) pxNewListItem;






/* Remember which list the item is in. */




pxNewListItem->pvContainer = ( void * ) pxList;






( pxList->uxNumberOfItems )++;



}



这些就不多说了。






2.


任务控制块




typedef struct tskTaskControlBlock



{




volatile portSTACK_TYPE


*pxTopOfStack;//


指向堆栈顶





xListItem


xGenericListItem;


//


通过它将任务连入就绪链表或者延时链表或


者挂起链表中




xListItem

< br>xEventListItem;//


通过它把任务连入事件等待链表

< p>




unsigned portBASE_TYPE


uxPriority;//


优先级





portSTACK_TYPE


*pxStack;


//


指向堆栈起始位置





signed portCHAR


pcTaskName[configMAX_TASK_NAME_LEN ];




#if ( portCRITICAL_NESTING_IN_TCB== 1 )




Unsigned portBASE_TYPE uxCriticalNesting;




#endif






#if (configUSE_TRACE_FACILITY == 1 )




Unsigned portBASE_TYPE


ux TCBNumber;//


用于


trace


debug


时候提供方便





#endif








#if ( configUSE_MUTEXES


== 1 )




unsigned


portBASE_TYPE uxBas ePriority;//


当用


mutex

发生优先级反转时用





#endif






#if (


configUSE_APPLICATION_TASK_TAG == 1 )




pdTASK_HOOK_CODE


pxTaskTag;




#endif






} tskTCB;


< p>
其中


uxBasePriority


用于解决优先 级反转,


freertos


采用优先级继承的办法解决这个问题 ,



继承时,将任务原先的优先级保存在这个成员中,将来再从 这里恢复任务的优先级。






3.


系统全局变量




freertos


将任务根据他们的 状态分成几个链表。所有就绪状态的任务根据任务优先级加到对


应的就绪链表中。系统为 每个优先级定义了一个


xList


。如下:



static xList pxReadyTasksLists[ configMAX_PRIORITIES ];


/*< Prioritised ready tasks. */



此外,所有延时的任务加入到两个延时链表之一。




static xList xDelayedTaskList1;




static xList xDelayedTaskList2;




还定义了两个指向延时链表的指针:




static xList * volatile pxDelayedTaskList;




static xList * volatile pxOverflowDelayedTaskList;






freertos


弄出两个延时链表 是因为它的延时任务管理的需要。


freertos


根据任务延 时时间的长


短按序将任务插入这两个链表之一。在插入前先把任务将要延时的

< p>
xTicksToDelay


数加上系


统当前


tick


数,这样得到了一个任务延时


du e time


(到期时间)的绝对数值。但是有可能这


个相加操 作会导致溢出,如果溢出则加入到


pxOverflowDelayedTaskLis t


指向的那个链表,否


则加入


pxDe layedTaskList


指向的链表。




freertos


还定义了个


pending


链表:




static xList xPendingReadyList;



这个链表用在调度 器被


lock


(就是禁止调度了)


的时 期,如果一个任务从非就绪状态变为就


绪状态,


它不直接加到就 绪链表中,


而是加到这个


pending


链表中。


等调度器重新启动


(unlock)


的时候再检查这个链表,把里面的任务加到就绪链表中






static volatile xList xTasksWaitingTermination;


/*< Tasks that have been deleted


- but the their memory not yet freed. */



static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned


portBASE_TYPE ) 0;


< br>一个任务被删除的时候加入到


xTasksWaitingTerminatio n


链表中,


uxTasksDeleted

跟中系统中


有多少任务被删除(即加到


xTasksWai tingTermination


链表的任务数目)


.



static xList xSuspendedTaskList;


/*<


Tasks that are currently suspended. */



这个链表记录着所有被


xTaskSuspend


挂起的任务,注意这不是那些等待信号量的 任务。






static


volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks

< p>
;记录了当前系统任务的数目




static


volatile portTickType xTickCount;


是自启动以来系统运行的


ticks< /p>





static


unsigned portBASE_TYPE uxTopUsedPriority


;记录当前系统中 被使用的最高优先级,




static


volatile unsigned portBASE_TYPE uxTopReadyPriority


;记录当前系统 中处于就绪状态的最高优


先级。




static


volatile signed portBASE_TYPE xSchedulerRunning


;

< p>
表示当前调度器是否在运行,也即内核是


否启动了






4.


任务管理




freertos



ucosii


不同,它的任务控制块并不是静态分配的,而是在创建任务的时候 动态分


配。另外,


freertos


的 优先级是优先级数越大优先级越高,和


ucosii


正好相反。 任务控制块


中也没有任务状态的成员变量,


这是因为

< p>
freertos


中的任务总是根据他们的状态连入对应的


链表,没有必要在任务控制块中维护一个状态。此外


freertos


对任务的数量没有限制,而且


同一个优先级可以有多个任务。

< p>





先看任务创建:



< br>/********************************************** *****************



**


参数


: pvTaskCode---


任务函数名称




** pcName---


任务名字,可选




**ucStackDepth---


任务堆栈的深度,即大小




**


p vParamenters---


参数,即传给任务函数的参数


,


所有的任务函数原型是


void


task


(void


*pvParameters)



** uxPriority



任务优先级




** pxCreatedTask



可选,通过它返回被创建任务的


tcb



*************************** ****************************************/



signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const


signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void


*pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask )



{



signed portBASE_TYPE xReturn;



tskTCB * pxNewTCB;



#if ( configUSE_TRACE_FACILITY == 1 )




static unsigned


portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is


guarded before use. */



#endif






/*


动态分配


tcb


和任务堆栈


* /




pxNewTCB =


prvAllocateTCBAndStack( usStackDepth );




/*


如果分配成功的话


*/




if( pxNewTCB != NULL )




{





portSTACK_TYPE


*pxTopOfStack;




/*


初始化


tcb*/




prvInitialiseTCBVariables(


pxNewTCB, pcName, uxPriority );






/*


计算堆栈的顶


*/




#if portSTACK_GROWTH


< 0




{




pxTopOfStack


= pxNewTCB->pxStack + ( usStackDepth - 1 );




}




#else




{




pxTopOfStack


= pxNewTCB->pxStack;





}




#endif






/*


初始化任务堆栈,并将返回地址保存在

< br>tcb


中的


pxTopOfStack

< br>变量


*/




pxNewTCB->pxTopOfStack


= pxPortInitialiseStack( pxTopOfStack, pvTaskCode, pvParameters );






/*


关中断


*/




portENTER_CRITICAL();




{ /*


更新系统的任务数


*/




uxCurrentNumberOfTasks++;




if(


uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )




{




/*


如果这是系统中第一个任务,则把它设为当前任务


*/




pxCurrentTCB


=


pxNewTCB;






/*


如果这是系统中的第一个任务,那也就意味着内核刚准备启 动,实际上这


第一个任务一定是


idle


任务,


这个时候我们要做一些系统初始化,


即初始化那些全局 链表


*/




prvInitialiseTaskLists();




}




else




{





/*


如果内核还没有运行,则把当前任务设成已经创建的任务 中优先级最高的那个


,


将来内核一


旦运 行,调度器会马上选择它运行


*/




if(


xSchedulerRunning == pdFALSE )




{




if(


pxCurrentTCB->uxPriority <= uxPriority )




{




pxCurrentTCB


= pxNewTCB;





}




}




}







/*


我们记录下当前使用的最高优先级,这为了方便任务调度< /p>


*/




if(


pxNewTCB->uxPriority > uxTopUsedPriority )




{




uxTopUsedPriority


= pxNewTCB->uxPriority;




}






#if (


configUSE_TRACE_FACILITY == 1 )





{




/*


Add a counter into the TCB for tracing only. */




pxNewTCB->uxTCBNumber


= uxTaskNumber;




uxTaskNumber++;




}




#endif




/*


把新创建的任务加到就绪链表


*/




prvAddTaskToReadyQueue(


pxNewTCB );






xReturn =


pdPASS;




traceTASK_CREATE(


pxNewTCB );




}





portEXIT_CRITICAL();




}



/*


如果分配内存失败,我们返回错 误


*/




else




{




xReturn =


errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;




traceTASK_CREATE_FAILED(


pxNewTCB );




}






if( xReturn == pdPASS )




{




if( ( void * )


pxCreatedTask != NULL )




{




/*


将新创建任务的


tcb

< p>
返回给调用者





*pxCreatedTask


= ( xTaskHandle ) pxNewTCB;




}




/*


如果调度器已经运行


*/




if(


xSchedulerRunning != pdFALSE )




{




/*


如果新创建的任务的优先级高于当前正在运行的任务,则调 度



*/




if(


pxCurrentTCB->uxPriority < uxPriority )




{




taskYIELD();




}




}




}






return xReturn;



}





其中


prvAllocateTCB AndStack


分配


tcb



stack


内存,这个里面调用了


pvpor tMalloc



pvPortFree


函数来分配和释放内存,


这两个函数对应于


C


标准库里面的


malloc



free



但是


标准库中的

< p>
mallo



free


存 在以下缺点:


并不是在所有的嵌入式系统中都可用,


要占用不定


的程序空间,可重人性欠缺以及执行时间具有不可确定性


,


而且多次反复调用可能导致严重


的内存碎片。因此

< br>freertos


在内存管理那块自己实现了这两个函数。




static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT


usStackDepth )



{



tskTCB *pxNewTCB;






/* Allocate space for


the TCB.


Where the memory comes from


depends on




the implementation of


the port malloc function. */




pxNewTCB = ( tskTCB * )


pvPortMalloc( sizeof( tskTCB ) );






if( pxNewTCB != NULL )




{




/* Allocate


space for the stack used by the task being created.




The base of the


stack memory stored in the TCB so the task can




be deleted later


if required. */




pxNewTCB->pxStack


= ( portSTACK_TYPE * ) pvPortMalloc( ( ( size_t )usStackDepth ) * sizeof(


portSTACK_TYPE ) );






if(


pxNewTCB->pxStack == NULL )




{




/* Could


not allocate the stack.


Delete the


allocated TCB. */




vPortFree(


pxNewTCB );





pxNewTCB


= NULL;





}





else




{




/* Just


to help debugging. */




memset(


pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE


) );




}




}






return pxNewTCB;



}





再看任务删除。



< br>freertos


的任务删除分两步完成,


第一步在


vTaskDelete


中完成,


Free RTOS


先把要删除的任务


从就绪任务链表和事件等待链表中删 除,然后把此任务添加到任务删除链表(即那个


xTasksWaitingTermi nation



,若删除的任务是当前运行任务,系统就执行任 务调度函数


.



2

步则是在


idle


任务中完成,


i dle


任务运行时,检查


xTasksWaitingTerm ination


链表,如果有任


务在这个表上,释放该任务占用 的内存空间,并把该任务从任务删除链表中删除。




/****************************************** **********************



**


参数:


pxTaskToDelete


是一 个指向被删除任务的句柄,这里其实就是等价于任务控制块




**


如果这个句柄


==NULL


,则表示要删除当前任务




********************************************** *********************/



void vTaskDelete( xTaskHandle pxTaskToDelete )



{




tskTCB


*pxTCB;






taskENTER_CRITICAL();




{




/*


如果删除的是当前任务,则删除完成后需要进行调度


*/




if(

-


-


-


-


-


-


-


-



本文更新与2021-02-11 15:01,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/637139.html

FreeRTOS进程管理的相关文章

  • 爱心与尊严的高中作文题库

    1.关于爱心和尊严的作文八百字 我们不必怀疑富翁的捐助,毕竟普施爱心,善莫大焉,它是一 种美;我们也不必指责苛求受捐者的冷漠的拒绝,因为人总是有尊 严的,这也是一种美。

    小学作文
  • 爱心与尊严高中作文题库

    1.关于爱心和尊严的作文八百字 我们不必怀疑富翁的捐助,毕竟普施爱心,善莫大焉,它是一 种美;我们也不必指责苛求受捐者的冷漠的拒绝,因为人总是有尊 严的,这也是一种美。

    小学作文
  • 爱心与尊重的作文题库

    1.作文关爱与尊重议论文 如果说没有爱就没有教育的话,那么离开了尊重同样也谈不上教育。 因为每一位孩子都渴望得到他人的尊重,尤其是教师的尊重。可是在现实生活中,不时会有

    小学作文
  • 爱心责任100字作文题库

    1.有关爱心,坚持,责任的作文题库各三个 一则150字左右 (要事例) “胜不骄,败不馁”这句话我常听外婆说起。 这句名言的意思是说胜利了抄不骄傲,失败了不气馁。我真正体会到它

    小学作文
  • 爱心责任心的作文题库

    1.有关爱心,坚持,责任的作文题库各三个 一则150字左右 (要事例) “胜不骄,败不馁”这句话我常听外婆说起。 这句名言的意思是说胜利了抄不骄傲,失败了不气馁。我真正体会到它

    小学作文
  • 爱心责任作文题库

    1.有关爱心,坚持,责任的作文题库各三个 一则150字左右 (要事例) “胜不骄,败不馁”这句话我常听外婆说起。 这句名言的意思是说胜利了抄不骄傲,失败了不气馁。我真正体会到它

    小学作文