任务的挂起与恢复:实时系统中 任务的暂停键与继续键!

[TOC]

一、简介

任务的挂起:即将任务从就绪列表中暂时移除,不再参与运行,恢复即把任务从新插入到就绪列表,继续运行

二、设置挂起恢复有关函数以及变量

挂起恢复有关变量(TCB中)

  • 任务TCB添加有关变量储存任务状态以及记录任务挂起的次数(挂起多少次就要恢复多少次才能继续插入就绪列表)
  • OS_STATE TaskState(记入任务状态)
  • OS_STATE u8类型重定义类型
  • SuspendCtr(挂起次数计数器)

    编写调度函数

    任务挂起函数

1
2
3
4
5
OSTaskSuspend
(
OS_TCB *tcb
OS_ERR *err
)//(任务挂起函数格式,以及其传递进去函数形式)
  1. 创建临界段调用参数
1
2
3
4
5
6
7
CPU_SR_ALLOC();
//展开(头文件中的定义)
/* 定义一个局部变量,用于保存CPU中断状态 */
#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0
#else
#define CPU_SR_ALLOC()
#endif
  1. 是否开启屏蔽
  • 根据宏定义判断一些任务的可执行性
  • ISR程序中不可调用挂起,否则报错
  • 中断处理函数不能挂起,否则报错
  • 空闲任务不能挂起,否则报错
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #if 0 /* 屏蔽开始 */
    #ifdef OS_SAFETY_CRITICAL
    /* 安全检查,OS_SAFETY_CRITICAL_EXCEPTION()函数需要用户自行编写 */
    if (p_err == (OS_ERR *)0) {
    OS_SAFETY_CRITICAL_EXCEPTION();
    return;
    }
    #endif

    #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
    /* 不能在ISR程序中调用该函数 */
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {
    *p_err = OS_ERR_TASK_SUSPEND_ISR;
    return;
    }
    #endif

    /* 不能挂起空闲任务 */
    if (p_tcb == &OSIdleTaskTCB) {
    *p_err = OS_ERR_TASK_SUSPEND_IDLE;
    return;
    }

    #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
    /* 不能挂起中断处理任务 */
    if (p_tcb == &OSIntQTaskTCB) {
    *p_err = OS_ERR_TASK_SUSPEND_INT_HANDLER;
    return;
    }
    #endif
  1. 进入临界段
1
CPU_CRITICAL_ENTER();
  1. 判断传入TCB==0?
  • 若等于0,则令TCB=OSTCBCurPtr
  • 不为0,判断若为OSTCBCurPtr ,则根据一个调度器宏定义变量判断,若调度器锁住,退出临界段,并报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 是否挂起自己 */
if (p_tcb == (OS_TCB *)0)
{
p_tcb = OSTCBCurPtr;
}
if (p_tcb == OSTCBCurPtr)
{
/* 如果调度器锁住则不能挂起自己 */
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0)
{
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_SCHED_LOCKED;
return;
}
}
*p_err = OS_ERR_NONE;
  1. 判断传入TCB的状态 switch判断
  • 非挂起状态进行挂起操作(状态切换为当前状态+挂起),挂起数目1,退出临界段和判断
  • 已经挂起的任务执行default,挂起数目+1,退出临界段和判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/* 根据任务的状态来决定挂起的动作 */
switch (p_tcb->TaskState)
{
case OS_TASK_STATE_RDY:
OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
OS_RdyListRemove(p_tcb);
OS_CRITICAL_EXIT_NO_SCHED();
break;

case OS_TASK_STATE_DLY:
p_tcb->TaskState = OS_TASK_STATE_DLY_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
CPU_CRITICAL_EXIT();
break;

case OS_TASK_STATE_PEND:
p_tcb->TaskState = OS_TASK_STATE_PEND_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
CPU_CRITICAL_EXIT();
break;

case OS_TASK_STATE_PEND_TIMEOUT:
p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
CPU_CRITICAL_EXIT();
break;

case OS_TASK_STATE_SUSPENDED:
case OS_TASK_STATE_DLY_SUSPENDED:
case OS_TASK_STATE_PEND_SUSPENDED:
case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
p_tcb->SuspendCtr++;
CPU_CRITICAL_EXIT();
break;

default:
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_STATE_INVALID;
return;
}
  1. 任务切换(任务状态改变后都要进行任务切换)
1
2
   /* 任务切换 */
OSSched();

任务挂起恢复函数

1
2
3
4
5
6
OSTaskResume
{
OS_TCB *p_tcb
OS_TCB *p_err
}
//(任务恢复函数,用于恢复被挂起的任务,无法恢复自己,函数形式如上)
  1. 创建临界段调用参数
    (同挂起函数)
  2. 是否开启屏蔽
     - 根据宏定义判断一些任务的可执行性
     - ISR程序中不可调用挂起,否则报错
     - 不能挂起当前任务自己
     (同上,因为没有空闲任务挂起,所以少一个)
  3. 判断任务状态,执行对应的恢复动作(switch判断)任务挂起数目递减;同时判断若挂起数量等于0,则将任务恢复到挂起之前状态(就绪、延迟、等待、等待+超时),再退出临界段
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    /* 根据任务的状态来决定恢复的动作 */
    switch (p_tcb->TaskState)
    {
    case OS_TASK_STATE_RDY:
    case OS_TASK_STATE_DLY:
    case OS_TASK_STATE_PEND:
    case OS_TASK_STATE_PEND_TIMEOUT:
    CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_TASK_NOT_SUSPENDED;
    break;

    case OS_TASK_STATE_SUSPENDED:
    OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
    p_tcb->SuspendCtr--;
    if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
    p_tcb->TaskState = OS_TASK_STATE_RDY;
    OS_TaskRdy(p_tcb);
    }
    OS_CRITICAL_EXIT_NO_SCHED();
    break;

    case OS_TASK_STATE_DLY_SUSPENDED:
    p_tcb->SuspendCtr--;
    if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
    p_tcb->TaskState = OS_TASK_STATE_DLY;
    }
    CPU_CRITICAL_EXIT();
    break;

    case OS_TASK_STATE_PEND_SUSPENDED:
    p_tcb->SuspendCtr--;
    if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
    p_tcb->TaskState = OS_TASK_STATE_PEND;
    }
    CPU_CRITICAL_EXIT();
    break;

    case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
    p_tcb->SuspendCtr--;
    if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
    p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT;
    }
    CPU_CRITICAL_EXIT();
    break;

    default:
    CPU_CRITICAL_EXIT();
    *p_err = OS_ERR_STATE_INVALID;
    return;
    }
  4. 任务切换

    三、调用流程

  5. 初始化
         - 任务TCB、创建变量;
1
2
3
4
5
6
7
8
9
10
11
*/
struct os_tcb
{
//任务状态标志
OS_STATE TaskState;
#if OS_CFG_TASK_SUSPEND_EN > 0u
/* 任务挂起函数OSTaskSuspend()计数器 */
OS_NESTING_CTR SuspendCtr;
#endif

};
  1. 调用
         - 在任务中直接根据需求使用
    1
    2
    3
    4
    //挂起
    OSTaskSuspend(&Task1TCB,&err);
    //恢复
    OSTaskResume(&Task1TCB,&err);