1-2中真的存在其他函数连续吗有一部小说,说只要找到机会无限循环!!!

 在前面的章节中笔者曾说过任務可以是一个无限的循环,也可以是在一次执行完毕后被删除掉 这里要注意的是,任务代码并不是被真正的删除了而只是?C/OS-Ⅱ不再理會该任务代码,所以该任务代码不会再运行任务看起来与任何C函数连续一样,具有 一个返回类型和一个参数只是它从不返回。任务的返回类型必须被定义成void型在本章中所提到的函数连续可以在OS_TASK文件中找到。如前所述任务 必须是以下两种结构之一:

 本章所讲的内容包括如何在用户的应用程序中建立任务、删除任务、改变任务的优先级、挂起和恢复任务,以及获得有关任务的信息
 ?C/OS-Ⅱ可以管理多达64个任务,并从中保留了四个最高优先级和四个最低优先级的任务供自己使用所以用户可以使用的只有56个任务。任务的优先级越高反映优先级的值则越低。在最新的?C/OS-Ⅱ版本中任务的优先级数也可作为任务的标识符使用。
OSTaskCreate()的扩展版本提供了一些附加的功能。用两个函数連续中的任何一个都可以建立任务任务可以在多任务调度开始前建立,也可以在其它 任务的执行过程中被建立在开始多任务调度(即调鼡OSStart())前,用户必须建立至少一个任务任务不能由中断服务程序(ISR)来建立。
 OSTaskCreate ()的代码如程序清单 L4.1所述从中可以知道,OSTaskCreate()需要四个参数:task是任务代碼的指针pdata是当任务开始执行时传递给任务的参数的指 针,ptos是分配给任务的堆栈的栈顶指针(参看4.02任务堆栈),prio是分配给任务的优先级

 OSTaskCreate ()一開始先检测分配给任务的优先级是否有效[L4.1(1)]。任务的优先级必须在0到OS_LOWEST_PRIO之间接着, OSTaskCreate()要确保在规定的优先级上还没有建立任务[L4.1(2)]在使用?C/OS-Ⅱ时,每个任务都有特定的优先级如果某个优 先级是空闲的,?C/OS-Ⅱ通过放置一个非空指针在OSTCBPrioTbl[]中来保留该优先级[L4.1(3)]这就使得 OSTaskCreate()在设置任务数据结構的其他部分时能重新允许中断[L4.1(4)]。
 然后OSTaskCreate()调用 OSTaskStkInit()[L4.1(5)],它负责建立任务的堆栈。该函数连续是与处理器的硬件体系相关的函数连续可以在OS_CPU_C.C文件中找 到。有关实现OSTaskStkInit()的细节可参看第8章——移植?C/OS-Ⅱ如果已经有人在你用的处理器上成功地移植了?C/OS-Ⅱ,而你 同它不支持用户为任务的创建过程设置不同的选项,所以没有任何选项可以通过opt参数传递给OSTaskStkInit()
 ?C/OS-Ⅱ 支持的处理器的堆栈既可以从上(高地址)往下(低地址)递减也可以从下往上递增。用户在调用OSTaskCreate()的时候必须知道堆栈是递增的还是 递减的(参看所用处理器的OS_CPU.H中的OS_STACK_GROWTH)因为用户必须得把堆栈的栈顶传递给OSTaskCreate(),而栈 OS_TCB[L4.2(1)]如果OS_TCB池中有空闲的OS_TCB[L4.2(2)],它就被初始化[L4.2(3)]。注意一旦OS_TCB 被分配该任务的创建者就已经完全拥有它了,即使这时内核又创建了其它的任务这些新任务吔不可能对已分配的OS_TCB作任何操作,所以 OSTCBInit()在这时就可以允许中断并继续初始化OS_TCB的数据单元。

OSTaskCreateHook()函数连续来初始化和存储浮点寄存器、MMU寄存器嘚内容或者其它与任务相关的内容。一般情况下用户可以在内存中存储 一些针对用户的应用程序的附加信息。OSTaskCreateHook()既可以在OS_CPU_C.C中定义(如果OS_CPU_HOOKS_EN置 1)也可以在其它地方定义。注意OSTaskCreate()在调用OSTaskCreateHook()时,中断是关掉的所以用户应该使 OSTaskCreateHook()函数连续中的代码尽量简化,因为这将直接影响中断的响应時间OSTaskCreateHook()在被调用时会收到指 向任务被建立时的OS_TCB的指针。这意味着该函数连续可以访问OS_TCB数据结构中的所有成员
 如果OSTaskCreate()函数连续是在某 个任务嘚执行过程中被调用(即OSRunning置为True[L4.1(10)]),则任务调度函数连续会被调用[L4.1(11)]来判断是否新建立的任 务比原来的任务有更高的优先级如果新任务的优先级哽高,内核会进行一次从旧任务到新任务的任务切换如果在多任务调度开始之前(即用户还没有调用 OSStart()),新任务就已经建立了,则任务调度函數连续不会被调用
 id参数为要建立的任务创建一个特殊的标识符。该参数在?C/OS以后的升级版本中可能会用到但在 ?C/OS-Ⅱ中还未使用。这个標识符可以扩展?C/OS-Ⅱ功能使它可以执行的任务数超过目前的64个。但在这里用户只要简单地将任务的id设置成 与任务的优先级一样的值就鈳以了。
 pbos是指向任务的堆栈栈底的指针用于堆栈的检验。
 stk_size用于指定堆栈成员数目的容量也就是说,如果堆栈的入口宽度为4字节宽那麼stk_size为10000是指堆栈有40000个字节。该参数与pbos一样也用于堆栈的检验。
 pext是指向用户附加的数据域的指针用来扩展任务的OS_TCB。例如用户可以为每个任务增加一个名字(参看实例3),或是在任务切换过程中将浮点寄存器的内容储存到这个附加数据域中等等。
每个选项占有opt的一位并通过該位的置位来选定(用户在使用时只需要将以上OS_TASK_OPT_???选项常数进行位或(OR)操作就可以了)。

某个优先级是空闲的?C/OS-Ⅱ通过放置一个非空指针在OSTCBPrioTbl[]中来保留该优先级[L4.3(3)]。这就使得 OSTaskCreateExt()在设置任务数据结构的其他部分时能重新允许中断[L4.3(4)]
 为了对任务的堆栈进行检验[参看 4.03,堆栈检验,OSTaskStkChk()]用户必须在opt参數中设置OS_TASK_OPT_STK_CHK标志。堆栈检验还要求在任务建 立时堆栈的存储内容都是0(即堆栈已被清零)为了在任务建立的时候将堆栈清零,需要在opt参数中设置OS_TASK_OPT_STK_CLR当以上 又得到了他的代码,就不必考虑该函数连续的实现细节了OSTaskStkInit()函数连续返回新的堆栈栈顶(psp),并被保存在任务的0S_TCB中。
 ?C/OS -Ⅱ支持的处理器的堆栈既可以从上(高地址)往下(低地址)递减也可以从下往上递增(参看4.02,任务堆栈)用户在调用 OSTaskCreateExt()的时候必须知道堆栈是递增的还是递减的(参看鼡户所用处理器的OS_CPU.H中的 OS_STACK_GROWTH),因为用户必须得把堆栈的栈顶传递给OSTaskCreateExt()而栈顶可能是堆栈的最低地址(当 户应该使OSTaskCreateHook()函数连续中的代码尽量简化,因為这将直接影响中断的响应时间OSTaskCreateHook()被调用时会 收到指向任务被建立时的OS_TCB的指针。这意味着该函数连续可以访问OS_TCB数据结构中的所有成员
 如果OSTaskCreateExt ()函数连续是在某个任务的执行过程中被调用的(即OSRunning置为True[L4.3(11)]),以任务调度函数连续会被调用[L4.3(12)]来判 断是否新建立的任务比原来的任务有更高的优先级如果新任务的优先级更高,内核会进行一次从旧任务到新任务的任务切换如果在多任务调度开始之前(即用户 还没有调用OSStart()),新任务僦已经建立了,则任务调度函数连续不会被调用
 每个任务都有自己的堆栈空间。堆栈必须声明为OS_STK类型并且由连续的内存空间组成。用户鈳以静态分配堆栈空间(在编译的时候分配)也可以动态地分配堆栈空间(在运行的时候分配)静态堆栈声明如程序清单 L4.4和4.5所示,这两种声明应放置在函数连续的外面

  用户可以用C编译器提供的malloc()函数连续来动态地分配堆栈空间,如程序清单 L4.6所示在动态分配中,用户要时刻注意内存碎片问题特别是当用户反复地建立和删除任务时,内存堆中可能会出现大量的内存碎片导致没有足够大的一 块连续内存区域可用作任务堆栈,这时malloc()便无法成功地为任务分配堆栈空间

  图4.1表示了一块能被malloc()动态分配的3K字节的内存堆 [F4.1(1)]。为了讨论问题方便假定用户要建立三個任务(任务A,B和C),每个任务需要1K字节的空间设第一个1K字节给任务A, 第二个1K字节给任务B, 第三个1K字节给任务C[F4.1(2)]。然后用户的应用程序删除任务A和任务C,用free()函数连续释放内存到内存堆中[F4.1(3)]现在, 用户的内存堆虽有2K字节的自由内存空间但它是不连续的,所以用户不能建立另一个需要2K芓节内存的任务(即任务D)如果用户并不会去删除任务,使用 malloc()是非常可行的

 ?C/OS-Ⅱ支持的处理器的堆栈既可以从上(高地址)往下(低地址) 长也可鉯从下往上长(参看4.02,任务堆栈)。用户在调用OSTaskCreate()或OSTaskCreateExt()的时候必须知道堆栈是怎样 长的因为用户必须得把堆栈的栈顶传递给以上两个函数连续,当OS_CPU.H攵件中的OS_STK_GROWTH置为0时用户需要将堆栈的最低内存地址传 递给任务创建函数连续,如程序清单4.7所示

 当OS_CPU.H文件中的OS_STK_GROWTH置为1时,用户需要将堆栈的最高内存地址传递给任务创建函数连续如程序清单4.8所示。

 这个问题会影响代码的可移植性如果用户想将代码从支持往下递减堆栈的处理器中移植到支持往上递增堆栈的处理器中的话,用户得使代码同时适应以上两种情况在这种特殊情况下,程序清单 L4.7和4.8可重新写成如程序清单 L4.9所示的形式

 任务所需的堆栈的容量是由应用程序指定的。用户在指定堆栈大小的时候必须考虑用户的任务所调用的所有函数连续的嵌套情况任务所调用的所有函数连续会分配的局部变量的数目,以及所有可能的中断服务例程嵌套的堆栈需求另外,用户的堆栈必须能储存所有的CPU寄存器
  有时候决定任务实际所需的堆栈空间大小是很有必要的。因为这样用户就可以避免为任务分配过多的堆栈空间从洏减少自己的应用程序代码所需的RAM(内存)数量。?C/OS-Ⅱ提供的OSTaskStkChk()函数连续可以为用户提供这种有价值的信息
  在图4.2中,笔者假定堆栈是从上往下遞减的(即OS_STK_GROWTH被置为1)但以下的讨论也同样适用于从下往上长的堆栈[F4.2(1)]。 ?C/OS-Ⅱ是通过查看堆栈本身的内容来决定堆栈的方向的只有内核或是任務发出堆栈检验的命令时,堆栈检验才会被执行它不会自动地去不断检验任务的 堆栈使用情况。在堆栈检验时?C/OS-Ⅱ要求在任务建立的時候堆栈中存储的必须是0值(即堆栈被清零)[F4.2(2)]。另外?C/OS-Ⅱ还需 要知道堆栈栈底(BOS)的位置和分配给任务的堆栈的大小[F4.2(2)]。在任务建立的时候BOS的位置及堆栈的这两个值储存在任务的OS_TCB 中。
 为了使用?C/OS-Ⅱ的堆栈检验功能用户必须要做以下几件事情:
用OSTaskCreateExt()建立任务,并给予任务比实际需要哽多的内存空间
CLR。注意如果用户的程序启动代码清除了所有的RAM并且从未删除过已建立了的任务,那么用户就不必设置选项OS_TASK_OPT_STK_CLR了这样就會减少OSTaskCreateExt()的执行时间。
将用户想检验的任务的优先级作为OSTaskStkChk()的参数并调用之

 OSTaskStkChk ()顺着堆栈的栈底开始计算空闲的堆栈空间大小,具体实现方法是統计储存值为0的连续堆栈入口的数目直到发现储存值不为0的堆栈入口[F4.2 (5)]。注意堆栈入口的储存值在进行检验时使用的是堆栈的数据类型(参看OS_CPU.H中的OS_STK)换句话说,如果堆栈的入口有32位宽对 0值的比较也是按32位完成的。所用的堆栈的空间大小是指从用户在OSTaskCreateExt()中定义的堆栈大小中减去叻储存值为0的连续堆栈入口 以后的大小OSTaskStkChk()实际上把空闲堆栈的字节数和已用堆栈的字节数放置在0S_STK_DATA数据结构中(参看?COS_Ⅱ. H)。注意在某个给定的時间被检验的任务的堆栈指针可能会指向最初的堆栈栈顶(TOS)与堆栈最深处之间的任何位置[F4.2(7)]。每次在调用 OSTaskStkChk()的时候用户也可能会因为任务还沒触及堆栈的最深处而得到不同的堆栈的空闲空间数。
 用户应该使自己的应用程序 运行足够长的时间并且经历最坏的堆栈使用情况,这樣才能得到正确的数一旦OSTaskStkChk()提供给用户最坏情况下堆栈的需求,用户就可以重 新设置堆栈的最后容量了为了适应系统以后的升级和扩展,用户应该多分配10%-100%的堆栈空间在堆栈检验中,用户所得到的只是一个大致的堆栈使用 情况并不能说明堆栈使用的全部实际情况。
 OSTaskStkChk()函数连续的代码如程序清单 L4.10所示0S_STK_DATA(参看?COS_Ⅱ.H)数据结构用来保存有关任务堆栈的信息。笔者打算用一个数据结构来达到两个目的第一,紦 OSTaskStkChk()当作是查询类型的函数连续并且使所有的查询函数连续用同样的方法返回,即返回查询数据到某个数据结构中第二,在数据结构中傳递数 据使得笔者可以在不改变OSTaskStkChk()的API(应用程序编程接口)的条件下为该数据结构增加其它域从而扩展OSTaskStkChk ()的功能。现在0S_STK_DATA只包含两个域:OSFree和OSUsed。从玳码中用户可看到通过指定执行堆栈检验的任务的优先级可以调用 OSTaskStkChk()。如果用户指定0S_PRIO_SELF[L4.10(1)]那么就表明用户想知道当前任务的堆栈信息。当然前提是任务 已经存在[L4.10(2)]。要执行堆栈检验用户必须已用OSTaskCreateExt()建立了任务并且已经传递了选项 OS_TASK_OPT_CHK[L4.10(3)]。如果所有的条件都满足了OSTaskStkChk()就会象前面描述的那样从堆栈栈底开始统计堆 栈的空闲空间[L4.10(4)]。最后储存在0S_STK_DATA中的信息就被确定下来了[L4.10(5)]。注意函数连续所确定的是堆栈的实际空闲 字节数和已被占用的字节数而不是堆栈的总字节数。当然堆栈的实际大小(用字节表示)就是该两项之和。

  有时候删除任务是很有必要的删除任务,昰说任务将返回并处于休眠状态(参看3.02,任务状态),并不是说任务的代码被删除了只是任务的代码不再被 ?C/OS-Ⅱ调用。通过调用OSTaskDel()就可以完成删除任务的功能(如程序清单 L4.11所示)OSTaskDel()一开始应确保用户所要删除的任务并非是空闲任务,因为删除空闲任务是不允许的[L4.11(1)]不过,用户 会保证被刪除的任务是确实存在的[L4.11(3)]如果指定的参数是OS_PRIO_SELF的话,这一判断过程(任务是否存在)自然是可以通过的 但笔者不准备为这种情况单独写一段玳码,因为这样只会增加代码并延长程序的执行时间

  一旦所有条件都满足了,OS_TCB就会从所有可能的?C/OS-Ⅱ的数据结构中移除OSTaskDel()分两步完成该迻除任务以减少中断响应时间。 首先如果任务处于就绪表中,它会直接被移除[L4.11(6)]如果任务处于邮箱、消息队列或信号量的等待表中,它僦从自己所处的表中被移除 就绪状态而是阻止其它任务或ISR例程让该任务重新开始执行(即避免其它任务或ISR调用OSTaskResume()[L4.11(9)])。这种情 况是有可能发生的因为OSTaskDel()会重新打开中断,而ISR可以让更高优先级的任务处于就绪状态这就可能会使用户想删除的任务重新开始执 行。如果不想置任务的.OSTCBStat标誌为OS_STAT_RDY就只能清除OS_STAT_SUSPEND位了(这样代码可能显得更清楚,更容 易理解一些)但这样会使得处理时间稍长一些。
 要被删除的任务不会被其它的任务戓ISR置于就绪状态因为该任务已从就绪任务表中删除了,它不 是在等待事件的发生也不是在等待延时期满,不能重新被执行为了达到刪除任务的目的,任务被置于休眠状态正因为这样,OSTaskDel()必须得阻 止任务调度程序[L4.11(10)]在删除过程中切换到其它的任务中去因为如果当前的任務正在被删除,它不可能被再次调度!接下来 OSTaskDel()重新允许中断以减少中断的响应时间[L4.11(11)]。这样OSTaskDel()就能处理中断服务了,但由于它增加了 OSLockNestingISR执荇完后会返回到被中断任务,从而继续任务的删除工作注意OSTaskDel()此时还没有完全完成删除任务的工 作,因为它还需要从TCB链中解开OS_TCB并将OS_TCB返回箌空闲OS_TCB表中。
 另外需要注意的是笔者在调用 OS_EXIT_CRITICAL()函数连续后,马上调用了OSDummy() [L4.11(12)]该函数连续并不会进行任何实质性的工作。这样做只是因为想确保处理器在中断允许的情况下至少执行一个指令对于许多处理器来说,执行 中断允许指令会强制CPU禁止中断直到下个指令结束!Intel 80x86和Zilog Z-80处理器僦是如此工作的开中断后马上关中断就等于从来没开过中断,当然这会增加中断的响应时间因此调用OSDummy()确保在再次禁止中断之 前至少执荇了一个调用指令和一个返回指令。当然用户可以用宏定义将OSDummy()定义为一个空操作指令(译者注:例如MC68HC08指令中的 NOP指令),这样调用OSDummy()就等于執行了一个空操作指令会使OSTaskDel()的执行时间稍微缩短一点。但笔者认为这种宏定义是没价 值的因为它会增加移植?COS-Ⅱ的工作量。
(17)]最后,調用任务调度程序来查看在OSTaskDel()重新允许中断的时候[L4.11(11)]中断服务子程序是否曾使更高优先级的任务 处于就绪状态[L4.11(18)]。
 有时候如果任务A拥有内存緩冲区或信号量之类的资源,而任务B想删除该任务这些资源就可能由于没被释放而丢失。在这种情况下用户可以想法子让拥有这些资源的任务在使用完资源后,先释放资源再删除自己。用户可以通过OSTaskDelReq()函数连续来完成该功能
  发出删除任务请求的任务(任务B)和要删除的任務(任务A)都需要调用OSTaskDelReq()函数连续。任务B的代码如程序清单 L4.12所示任务B需要决定在怎样的情况下请求删除任务[L4.12(1)]。换句话说用户的应用程序需要決定在什么样的情况下删除任务。如果任务 表明请求已被接受但任务还没被删除用户可能希望任务B等到任务A删除了自己以后才继续进行丅面的工作,这时用户可以象笔者一样通过让任务B延时一定时 间来达到这个目的[L4.12(3)]。笔者延时了一个时钟节拍如果需要,用户可以延时嘚更长一些当任务A完全删除自己后,[L4.12(2)]中的 返回值成为0S_TASK_NOT_EXIST此时循环结束[L4.12(4)]。

有另外的任务请求该任务被删除了在这种情况下,被删除的任務会释放它所拥有的所用资源[L4.13(2)]并且调用OSTaskDel (OS_PRIO_SELF)来删除自己[L4.13(3)]。前面曾提到过任务的代码没有被真正的删除,而只是?C/OS-Ⅱ不再理会该任务代码換 句话说,就是任务的代码不会再运行了但是,用户可以通过调用OSTaskCreate()或OSTaskCreateExt()函数连续重新建立该任务
 OSTaskDelReq ()的代码如程序清单 L4.14所示。通常OSTaskDelReq()需要检查臨界条件首先,如果正在删除的任务是空闲任务OSTaskDelReq()会报错并返回 [L4.14(1)]。接着它要保证调用者请求删除的任务的优先级是有效的[L4.14(2)]。如果调用鍺就是被删除任务本身存储在OS_TCB中


 在用户建立任务的时候会分配给任务一个优先级。在程序运行期间用户可以通过调用OSTaskChangePrio()来改变任务的优先级。换句话说就是?C/OS-Ⅱ允许用户动态的改变任务的优先级。
 OSTaskChangePrio ()的代码如程序清单 L4.15所示用户不能改变空闲任务的优先级[L4.15(1)],但用户可以改變调用本函数连续的任务或者其它任务的优先级为了改变调用本函数连续的任务的 优先级,用户可以指定该任务当前的优先级或OS_PRIO_SELFOSTaskChangePrio()会决萣该任务的优先级。用户还必须指定任务的 新(即想要的)优先级因为?C/OS-Ⅱ不允许多个任务具有相同的优先级,所以OSTaskChangePrio()需要检验新优先级是否昰合法的(即 不存在具有新优先级的任务)[L4.15(2)]如果新优先级是合法的,?C/OS-Ⅱ通过将某些东西储存到OSTCBPrioTbl 预先计算新优先级任务的OS_TCB中的某些值[L4.15(4)]洏这些值用来将任务放入就绪表或从该表中移除(参看3.04,就绪表)。
  接着OSTaskChangePrio()检验目前的任务是否想改变它的优先级[L4.15(5)]。然后OSTaskChangePrio()检查 想要改变优先级嘚任务是否存在[L4.15(6)]。很明显如果要改变优先级的任务就是当前任务,这个测试就会成功但是,如果 OSTaskChangePrio()想要改变优先级的任务不存在它必須将保留的新优先级放回到优先级表OSTCBPrioTbl[]中[L4.15 (17)],并返回给调用者一个错误码
 现在,OSTaskChangePrio()可以通过插入NULL指针将指向当前任务OS_TCB的指 针从优先级表中移除叻[L4.15(7)]这就使得当前任务的旧的优先级可以重新使用了。接着我们检验一下OSTaskChangePrio()想要 改变优先级的任务是否就绪[L4.15(8)]。如果该任务处于就绪状态咜必须在当前的优先级下从就绪表中移除[L4.15(9)],然后在新的优先级 下插入到就绪表中[L4.15(10)]这儿需要注意的是,OSTaskChangePrio()所用的是重新计算的值[L4.15(4)]将任务插入 僦绪表中的
 如果任务已经就绪,它可能会正在等待一个信号量、一封邮件或是一个消息队列如果OSTCBEventPtr非空(不等于 NULL)[L4.15(8)],OSTaskChangePrio()就会知道任务正在等待以上的某件事如果任务在等待某一事件的发生, 性的步骤后在新的优先级高于旧的优先级或新的优先级高于调用本函数连续的任務的优先级情况下,任务调度程序就会被调用[L4.15(16)]

  有时候将任务挂起是很有用的。挂起任务可通过调用OSTaskSuspend()函数连续来完成被挂起的任务只能通过调用OSTaskResume()函数连续 来恢复。任务挂起是一个附加功能也就是说,如果任务在被挂起的同时也在等待延时的期满那么,挂起操作需要被取消而任务继续等待延时期满,并转入就绪 状态任务可以挂起自己或者其它任务。
 OSTaskSuspend()函数连续的代码如程序清单 L4.16所示通常OSTaskSuspend()需要检验临堺条件。首先OSTaskSuspend()要确保用户的应用程序不是在挂起空闲任务 [L4.16(1)],接着确认用户指定优先级是有效的[L4.16(2)]记住最大的有效的优先级数(即最低的优先级)是 OS_LOWEST_PRIO。注意用户可以挂起统计任务(statistic)。可能用户已经注意到了第一个测试[L4.16(1)]在 [L4.16(2)]中被重复了。笔者这样做是为了能与?C/OS兼容第一个測试能够被移除并可以节省一点程序处理的时间,但是这样做的意义不大,所 以笔者决定留下它
 接着,OSTaskSuspend()检验用户是否通过指定OS_PRIO_SELF来挂起調用本函数连续的任务本身 [L4.16(3)]用户也可以通过指定优先级来挂起调用本函数连续的任务[L4.16(4)]。在这两种情况下任务调度程序都需要被调用。這就是笔者为 什么要定义局部变量self的原因该变量在适当的情况下会被测试。如果用户没有挂起调用本函数连续的任务OSTaskSuspend()就没有必要运行任 务调度程序,因为正在挂起的是较低优先级的任务
 然后,OSTaskSuspend()检验要挂起的任务是否存在[L4.16(5)]如果该 任务存在的话,它就会从就绪表中被移除[L4.16(6)]注意要被挂起的任务有可能没有在就绪表中,因为它有可能在等待事件的发生或延时的期满在这 种情况下,要被挂起的任务在OSRdyTbl[]中对應的位已被清除了(即为0)再次清除该位,要比先检验该位是否被清除了再在它没被清除时清除它快得 多所以笔者没有检验该位而直接清除它。现在OSTaskSuspend()就可以在任务的OS_TCB中设置OS_STAT_SUSPEND标志了, 以表明任务正在被挂起[L4.16(7)]最后,OSTaskSuspend()只有在被挂起的任务是调用本函数连续的任务本身的情况下財调用任务调度程序 [L4.16(8)]

  在上一节中曾提到过,被挂起的任务只有通过调用OSTaskResume()才能恢复OSTaskResume()函数连续的代码如程序清单 L4.17所示。因为OSTaskSuspend()不能挂起空闲任务所以必须得确认用户的应用程序不是在恢复空闲任务[L4.17(1)]。注意这 [L4.17(4)]。要使任务处于就绪状态OS_TCBDly域必须为0[L4.17(5)],这是因为在OSTCBStat中没有任何标志表明任务 正在等待延时的期满只有当以上两个条件都满足的时候,任务才处于就绪状态[L4.17(6)]最后,任务调度程序会检查被恢复的任务拥有嘚优先级是否 比调用本函数连续的任务的优先级高[L4.17(7)]

  用户的应用程序可以通过调用OSTaskQuery()来获得自身或其它应用任务的信息。实际上OSTaskQuery()获得的是對应任务的 OS_TCB中内容的拷贝。用户能访问的OS_TCB的数据域的多少决定于用户的应用程序的配置(参看OS_CFG.H)由于?C/OS-Ⅱ是可裁剪 的,它只包括那些用户的應用程序所要求的属性和功能
 要调用OSTaskQuery(),如程序清单 L4.18中所示的那样用户的应用程序必须要为OS_TCB分配存储空间。这个OS_TCB与?C/OS-Ⅱ分配的OS_TCB是完全不哃的数据空间 在调用了OSTaskQuery()后,这个OS_TCB包含了对应任务的OS_TCB的副本用户必须十分小心地处理OS_TCB中指向其它 OS_TCB的指针(即OSTCBNext与OSTCBPrev);用户不要试图去改变这些指针!一般来说,本函数连续只用来了解任务正在干什么——本函数连续是 有用的调试工具

 OSTaskQuery ()的代码如程序清单 L4.19所示。注意笔者允许用戶查询所有的任务,包括空闲任务[L4.19(1)]用户尤其需要注意的是不要改变OSTCBNext与 OSTCBPrev的指向。通常OSTaskQuery()需要检验用户是否想知道当前任务的有关信息[L4.19(2)]以及該任务是否已经建立了 [L4.19(3)]。所有的域是通过赋值语句一次性复制的而不是一个域一个域地复制的[L4.19(4)]这样复制会比较快一点,因为编译器大多嘟能 够产生内存拷贝指令

我要回帖

更多关于 函数连续 的文章

 

随机推荐