第4章第5节 任务创建和任务删除钩…

来源:互联网 发布:中国程序员联合开发网 编辑:程序博客网 时间:2024/05/20 10:22


目前更新到5.3节,请在
http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档

本节源代码请在http://dl.dbank.com/c0t7gmgx2q下载

 

第5节 任务创建和任务删除钩子函数

上节增加了任务切换钩子功能,打印出任务切换的信息,本节将增加任务创建钩子函数和任务删除钩子函数,分别打印出任务创建和删除的信息。

 

任务创建和删除钩子函数的原理与任务切换钩子函数的原理是一样的,都是需要定义一个与被挂接函数类型一致的指针型全局变量,使用钩子添加函数将被执行的函数挂接到钩子变量上,不同的是任务创建钩子函数在任务创建后打印,任务删除钩子函数在任务删除后打印。

钩子变量定义如下:

VFHCRT gvfTaskCreateHook;

VFHDLT gvfTaskDeleteHook;

VFHCRTVFHDLT的定义为:

typedef void    (*VFHCRT)(M_TCB*);

typedef void    (*VFHDLT)(M_TCB*);

被挂接的任务创建函数如下,与任务创建全局变量gvfTaskCreateHook类型一致,它会打印被创建函数的名称及创建的时间。

00071  void TEST_TaskCreatePrint(M_TCB* pstrTcb)

00072  {

00073      

00074      if((M_TCB*)NULL != pstrTcb)

00075      {

00076          DEV_PutStrToMem((U8*)"\r\nTask %s is created! Tick is: %d",

00077                          pstrTcb->pucTaskName, MDS_SystemTickGet());

00078      }

00079      else 

00080      {

00081          DEV_PutStrToMem((U8*)"\r\nFail to create task! Tick is: %d",

00082                          MDS_SystemTickGet());

00083      }

00084  }

 

被挂接的任务删除函数如下,与任务删除全局变量gvfTaskDeleteHook类型一致,它会打印被删除函数的名称及删除的时间。

00104  void TEST_TaskDeletePrint(M_TCB* pstrTcb)

00105  {

00106      DEV_PutStrToMem((U8*)"\r\nTask %s is deleted! Tick is: %d",

00107                      pstrTcb->pucTaskName, MDS_SystemTickGet());

00108  }

 

如果需要使用钩子创建函数则需要在创建任务的函数MDS_TaskCreate里增加钩子函数代码,如下:

00023  M_TCB* MDS_TaskCreate(U8* pucTaskName, VFUNC vfFuncPointer, U8* pucTaskStack,

00024                        U32 uiStackSize, U8 ucTaskPrio, M_TASKOPT* pstrTaskOpt)

00025  {

00026  

……       ……

00094  

00095      

00096      if((MDS_RootTask != vfFuncPointer) && (MDS_IdleTask != vfFuncPointer))

00097      {

00098  #ifdef MDS_INCLUDETASKHOOK

00099  

00100          

00101          if((VFHCRT)NULL != gvfTaskCreateHook)

00102          {

00103              gvfTaskCreateHook(pstrTcb);

00104          }

00105  

00106  #endif

00107  

00108          

00109          MDS_TaskSwiSched();

00110      }

00111  

00112      return pstrTcb;

00113  }

00026~00094行,代码与上节完全一样。

00096行,只有非系统任务才执行任务创建钩子函数。

00101~00104行,若挂接了任务创建钩子函数则执行。

 

本节我们需要增加一个删除任务的函数MDS_TaskDelete,用它来删除任务,在删除任务时可以执行挂接的任务删除钩子函数。

任务创建时在任务栈里创建了TCBTCB中的ready节点和delay节点可能会挂接到ready表和delay表,我们只要将任务从ready表和delay表拆除,操作系统就无法再调度这个任务了,这样就可以删除该任务。删除后任务的任务栈中的数据还是存在的,但由于任务已经无法与ready表和delay表关联,因此这些数据就变成了无效数据。任务删除时,任务所使用的任务栈内存应该也被释放掉,但目前任务栈的内存是由用户申请的而不是由操作系统申请的,因此需要用户自行释放任务栈内存,操作系统不进行管理。以后任务栈由操作系统申请时,MDS_TaskDelete函数才负责释放这部分内存。

00121  U32 MDS_TaskDelete(M_TCB* pstrTcb)

00122  {

00123      M_CHAIN* pstrChain;

00124      M_CHAIN* pstrNode;

00125      M_PRIOFLAG* pstrPrioFlag;

00126      U8 ucTaskPrio;

00127      U8 ucTaskSta;

00128  

00129      

00130      if(NULL == pstrTcb)

00131      {

00132          return RTN_FAIL;

00133      }

00134  

00135      

00136      if(pstrTcb == gpstrIdleTaskTcb)

00137      {

00138          return RTN_FAIL;

00139      }

00140  

00141      (void)MDS_IntLock();

00142  

00143      

00144      ucTaskSta pstrTcb->strTaskOpt.ucTaskSta;

00145  

00146      

00147      if(TASKREADY == (TASKREADY ucTaskSta))

00148      {

00149          

00150          ucTaskPrio pstrTcb->ucTaskPrio;

00151          pstrChain &gstrReadyTab.astrChain[ucTaskPrio];

00152          pstrPrioFlag &gstrReadyTab.strFlag;

00153  

00154          

00155          (void)MDS_TaskDelFromSchedTab(pstrChain, pstrPrioFlag, ucTaskPrio);

00156      }

00157  

00158      

00159      if(DELAYQUEFLAG == (pstrTcb->uiTaskFlag DELAYQUEFLAG))

00160      {

00161          

00162          pstrNode &pstrTcb->strDelayQue.strQueHead;

00163  

00164          

00165          (void)MDS_ChainCurNodeDelete(&gstrDelayTab, pstrNode);

00166      }

00167  

00168      (void)MDS_IntUnlock();

00169  

00170  #ifdef MDS_INCLUDETASKHOOK

00171  

00172      

00173      if((VFHDLT)NULL != gvfTaskDeleteHook)

00174      {

00175          gvfTaskDeleteHook(pstrTcb);

00176      }

00177  

00178  #endif

00179  

00180      

00181      MDS_TaskSwiSched();

00182  

00183      return RTN_SUCD;

00184  }

00121行,函数有2种返回值,RTN_SUCD代表任务删除成功,RTN_FAIL代表任务删除失败。入口参数pstrTcb是需要被删除的任务的TCB指针。

00130~00133行,入口参数检查,入口参数为空则返回失败。

00136~00139行,入口参数检查,若删除idle任务则返回失败。

00141行,锁中断。下面将操作ready表和delay表,为防止多个任务同时操作这两个表,需要锁中断。

00144行,获取被删除任务的当前任务状态。

00147~00156行,若该任务在ready表中则从ready表删除。

00159~00166行,若该任务在delay表中则从delay表删除。

00168行,调度表操作完成,解锁中断。

00170~00178行,若挂接了任务删除钩子函数则执行该函数。

00181行,任务已经被删除,需要重新调度一次任务。

 

本节内容较少,主要内容已经介绍完毕。本节仍使用上节的3个功能验证函数,与上节不同的是在8000 ticks的时候TEST_TestTask3任务会被root任务删除,在10000 ticksroot任务也会被自己删除。

00014  void MDS_RootTask(void)

00015  {

00016      M_TCB* pstrTcb;

00017      M_TASKOPT strOption;

00018  

00019      

00020      DEV_SoftwareInit();

00021  

00022      

00023      DEV_HardwareInit();

00024  

00025      

00026      (void)MDS_TaskCreate((U8*)"Test1", (VFUNC)TEST_TestTask1, gaucTask1Stack,

00027                           TASKSTACK, 2, (M_TASKOPT*)NULL);

00028  

00029      

00030      strOption.ucTaskSta TASKREADY;

00031      (void)MDS_TaskCreate((U8*)"Test2", (VFUNC)TEST_TestTask2, gaucTask2Stack,

00032                           TASKSTACK, 3, &strOption);

00033  

00034      

00035      strOption.ucTaskSta TASKDELAY;

00036      strOption.uiDelayTick 2000;

00037      pstrTcb MDS_TaskCreate((U8*)"Test3", (VFUNC)TEST_TestTask3, gaucTask3Stack,

00038                               TASKSTACK, 1, &strOption);

00039  

00040      (void)MDS_TaskDelay(8000);

00041  

00042      

00043      (void)MDS_TaskDelete(pstrTcb);

00044  

00045      (void)MDS_TaskDelay(2000);

00046  

00047      

00048      (void)MDS_TaskDelete(MDS_CurrentTcbGet());

00049  }

root任务起来后创建了3个任务,我们会看到这3个任务创建过程的打印,随后任务运行的过程与上节一致。当系统运行到8000 ticks时,TEST_TestTask3任务会被删除,我们可以看到TEST_TestTask3任务被删除的打印信息,此后就只有TEST_TestTask1TEST_TestTask2任务在运行了。到10000 ticks时,root任务调用MDS_TaskDelete函数将自己删除,无需再调用MDS_TaskDelay(DELAYWAITFEV)函数进入永久delay状态。

本节运行结果截图如下:

第4章第5节 <wbr>任务创建和任务删除钩子函数

图 48  带有任务创建、切换和删除过程的打印

读者可以访问http://blog.sina.com.cn/ifreecoding网站下载视频,观看全部数据的打印过程,可以看到实际运行的结果与我们上面推断的结果是一致的。

使用工具软件将任务切换过程的数据解析为图形,结果如下图所示:

 第4章第5节 <wbr>任务创建和任务删除钩子函数

图 49  4.5节任务切换过程图

从图中可以清晰的看到2000 ticksTEST_TestTask3任务结束delay状态,开始运行,在8000 ticks时,root任务delay时间耗尽,操作系统切换到root任务,删除了TEST_TestTask3任务,在10000 ticks时,root任务delay时间再次耗尽,操作系统切换到root任务,删除了自己。此后只剩下TEST_TestTask1TEST_TestTask2任务切换运行。

原创粉丝点击