freertos任务管理.doc_第1页
freertos任务管理.doc_第2页
freertos任务管理.doc_第3页
freertos任务管理.doc_第4页
freertos任务管理.doc_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

freertos是一个轻量级的rtos,它目前实现了一个微内核,并且port到arm7, avr, pic18, coldfire等众多处理器上;目前已经在rtos的市场上占有不少的份额。它当然不是一个与vxworks之类的rtos竞争的操作系统,它的目标在 于低性能小RAM的处理器上。整个系统只有3个文件,外加上port的和处理器相关的两个文件,实现是很简洁的。与ucosii不同,它是free的,ucosii不是free的,虽然它的代码是公开的。FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理。FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU总是让处于就绪态的、 优先级最高的任务先运行。FreeRT0S内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。这一点是和ucosii不同的。另外一点不同是freertos既可以配置为可抢占内核也可以配置为不可抢占内核。当FreeRTOS被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这 样可提高CPU的运行效率。这篇文章是以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 uxNumberOfItems;/表示该链表中节点的数目 volatile xListItem * pxIndex;/用于遍历链表,指向上次访问的节点 volatile xMiniListItem xListEnd;/链表尾结点 /*指向链表中的最后一个节点?*/ xList;而下面这个数据结构用在xList中,只是为了标记一个链表的尾,是一个markerstruct xMINI_LIST_ITEM portTickType xItemValue; volatile struct xLIST_ITEM *pxNext; volatile struct xLIST_ITEM *pxPrevious;typedef struct xMINI_LIST_ITEM xMiniListItem;对于链表的操作也定义了一系列的函数和宏,在list.c文件中。如初始化个链表,吧一个节点插入链表等。初始化链表: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 endis 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-xListEnd.xItemValue = portMAX_DELAY; /* The list end next and previous pointers point to itselfso we know when the list is empty. */ pxList-xListEnd.pxNext = ( xListItem * ) &(pxList-xListEnd ); pxList-xListEnd.pxPrevious = ( 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 sortthe list, makes the new list item the last item to be removed by acall to pvListGetOwnerOfNextEntry.This means it has to be theitem 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 tskTaskControlBlockvolatile portSTACK_TYPE *pxTopOfStack; /指向堆栈顶xListItem xGenericListItem; /通过它将任务连入就绪链表或者延时链表或者挂起链表中xListItem xEventListItem; /通过它把任务连入事件等待链表unsigned portBASE_TYPE uxPriority; /优先级portSTACK_TYPE *pxStack; /指向堆栈起始位置signed portCHAR pcTaskNameconfigMAX_TASK_NAME_LEN ;#if ( portCRITICAL_NESTING_IN_TCB= 1 )unsignedportBASE_TYPE uxCriticalNesting;#endif#if (configUSE_TRACE_FACILITY = 1 )unsignedportBASE_TYPE uxTCBNumber; /用于trace,debug时候提供方便#endif#if ( configUSE_MUTEXES= 1 )unsignedportBASE_TYPE uxBasePriority; /当用mutex发生优先级反转时用#endif#if (configUSE_APPLICATION_TASK_TAG = 1 )pdTASK_HOOK_CODEpxTaskTag;#endif tskTCB;其中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根据任务延时时间的长短按序将任务插入这两个链表之一。在插入前先把任务将要延时的xTicksToDelay数加上系统当前tick数,这样得到了一个任务延时due time(到期时间)的绝对数值。但是有可能这个相加操作会导致溢出,如果溢出则加入到pxOverflowDelayedTaskList指向的那个链表,否则加入pxDelayedTaskList指向的链表。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 = ( unsignedportBASE_TYPE ) 0;一个任务被删除的时候加入到xTasksWaitingTermination链表中,uxTasksDeleted跟中系统中有多少任务被删除(即加到xTasksWaitingTermination链表的任务数目).static xList xSuspendedTaskList;/*Tasks that are currently suspended. */这个链表记录着所有被xTaskSuspend挂起的任务,注意这不是那些等待信号量的任务。staticvolatile unsigned portBASE_TYPE uxCurrentNumberOfTasks ;记录了当前系统任务的数目staticvolatile portTickType xTickCount;是自启动以来系统运行的ticks数staticunsigned portBASE_TYPE uxTopUsedPriority;记录当前系统中被使用的最高优先级,staticvolatile unsigned portBASE_TYPE uxTopReadyPriority;记录当前系统中处于就绪状态的最高优先级。staticvolatile signed portBASE_TYPE xSchedulerRunning;表示当前调度器是否在运行,也即内核是否启动了4.任务管理freertos与ucosii不同,它的任务控制块并不是静态分配的,而是在创建任务的时候动态分配。另外,freertos的优先级是优先级数越大优先级越高,和ucosii正好相反。任务控制块中也没有任务状态的成员变量,这是因为freertos中的任务总是根据他们的状态连入对应的链表,没有必要在任务控制块中维护一个状态。此外freertos对任务的数量没有限制,而且同一个优先级可以有多个任务。先看任务创建:/*参数: pvTaskCode-任务函数名称* pcName-任务名字,可选*ucStackDepth-任务堆栈的深度,即大小* pvParamenters-参数,即传给任务函数的参数,所有的任务函数原型是void task (void *pvParameters)* uxPriority任务优先级* pxCreatedTask可选,通过它返回被创建任务的tcb*/signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, constsigned 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 unsignedportBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this isguarded before use. */#endif/*动态分配tcb和任务堆栈*/pxNewTCB =prvAllocateTCBAndStack( usStackDepth );/*如果分配成功的话*/if( pxNewTCB != NULL )portSTACK_TYPE*pxTopOfStack;/*初始化tcb*/prvInitialiseTCBVariables(pxNewTCB, pcName, uxPriority );/*计算堆栈的顶*/#if portSTACK_GROWTHpxStack + ( usStackDepth - 1 );#elsepxTopOfStack= pxNewTCB-pxStack;#endif/* 初始化任务堆栈,并将返回地址保存在tcb中的pxTopOfStack变量*/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 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();/*如果分配内存失败,我们返回错误*/elsexReturn =errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;traceTASK_CREATE_FAILED(pxNewTCB );if( xReturn = pdPASS )if( ( void * )pxCreatedTask != NULL )/*将新创建任务的tcb返回给调用者*pxCreatedTask= ( xTaskHandle ) pxNewTCB;/*如果调度器已经运行*/if(xSchedulerRunning != pdFALSE )/*如果新创建的任务的优先级高于当前正在运行的任务,则调度 */if(pxCurrentTCB-uxPriority pxStack= ( portSTACK_TYPE * ) pvPortMalloc( ( ( size_t )usStackDepth ) * sizeof(portSTACK_TYPE ) );if(pxNewTCB-pxStack = NULL )/* Couldnot allocate the stack. Delete theallocated TCB. */vPortFree(pxNewTCB );pxNewTCB= NULL;else/* Justto help debugging. */memset(pxNewTCB-pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE) );return pxNewTCB;再看任务删除:freertos的任务删除分两步完成,第一步在vTaskDelete中完成,FreeRTOS先把要删除的任务从就绪任务链表和事件等待链表中删除,然后把此任务添加到任务删除链表(即那个xTasksWaitingTermination),若删除的任务是当前运行任务,系统就执行任务调度函数.第2步则是在idle任务中完成,idle任务运行时,检查xTasksWaitingTermination链表,如果有任务在这个表上,释放该任务占用的内存空间,并把该任务从任务删除链表中删除。/*参数:pxTaskToDelete是一个指向被删除任务的句柄,这里其实就是等价于任务控制块*如果这个句柄=NULL,则表示要删除当前任务*/void vTaskDelete( xTaskHandle pxTaskToDelete )tskTCB*pxTCB;taskENTER_CRITICAL();/* 如果删除的是当前任务,则删除完成后需要进行调度*/if(pxTaskToDelete = pxCurrentTCB )pxTaskToDelete= NULL;/*通过传进来的任务句柄得到对应的tcb*/pxTCB= prvGetTCBFromHandle( pxTaskToDelete );traceTASK_DELETE(pxTCB );/* 把任务从就绪链表或者延时链表或者挂起链表中删除*/vListRemove(&( pxTCB-xGenericListItem ) );/* 判断任务是否在等待事件(semaphore消息队列等) */if(pxTCB-xEventListItem.pvContainer )/如果是,则把它从事件等待链表中删除vListRemove(&( pxTCB-xEventListItem ) );/插入等待删除链表vListInsertEnd( xList * ) &xTasksWaitingTermination, &( pxTCB-xGenericListItem );/增加uxTasksDeleted计数+uxTasksDeleted;taskEXIT_CRITICAL();/*如果调度器已经运行,并且删除的是当前任务,则调度*/if(xSchedulerRunning != pdFALSE )if( void * ) pxTaskToDelete = NULL )taskYIELD();再看空闲任务做的第2步工作:static portTASK_FUNCTION( prvIdleTask, pvParameters)/* Stopwarnings. */( void )pvParameters;for( ; )/* Seeif

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论