uC/OS-III之任务信号量

1.给任务发布信号量是一种非常常用的同步方法,因此,在uC/OS-III中,每个任务都有它自己的内嵌信号量。

2.当创建任务时,任务信号量会被自动创建,且初始计数为零。

3.等待任务信号量使用函数OSTaskSemPend(),它的定义位于os_task.c中。

OS_SEM_CTR  OSTaskSemPend (OS_TICK   timeout,                // 1190行 - 1293行,超时时间
                           OS_OPT    opt,                    // 等待的方式
                           CPU_TS   *p_ts,                   // 时间戳
                           OS_ERR   *p_err)                  // 错误码
{
    OS_SEM_CTR    ctr;
    CPU_SR_ALLOC();                                          // 声明变量cpu_sr,用来临时存储CPU的状态寄存器

#ifdef OS_SAFETY_CRITICAL                                   // 允许进行系统安全性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_SEM_CTR)0);
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u                      // 允许进行ISR调用检查
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 不允许在ISR中调用
       *p_err = OS_ERR_PEND_ISR;
        return ((OS_SEM_CTR)0);
    }
#endif

    if (p_ts != (CPU_TS *)0) {
       *p_ts  = (CPU_TS  )0;                                // 初始化返回的时间戳
    }

    CPU_CRITICAL_ENTER();                                   // 进入临界区
    if (OSTCBCurPtr->SemCtr > (OS_SEM_CTR)0) {              // 计数值 > 0,表示信号量可用
        OSTCBCurPtr->SemCtr--;                              // 计数值减1
        ctr    = OSTCBCurPtr->SemCtr;
        if (p_ts != (CPU_TS *)0) {
           *p_ts  = OSTCBCurPtr->TS;
        }
#if OS_CFG_TASK_PROFILE_EN > 0u                             // ???
        OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS;
        if (OSTCBCurPtr->SemPendTime > OSTCBCurPtr->SemPendTimeMax) {
            OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime;
        }
#endif
        CPU_CRITICAL_EXIT();                                // 退出临界区
        *p_err = OS_ERR_NONE;
        return (ctr);
    }
                                                            // 计数值 == 0,信号量不可用
    if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {    // 非阻塞型
        CPU_CRITICAL_EXIT();                                // 退出临界区
        *p_err = OS_ERR_PEND_WOULD_BLOCK;
        return ((OS_SEM_CTR)0);
    } else {                                                // 阻塞型
        if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {    // 任务调度器锁定,无法挂起任务
            CPU_CRITICAL_EXIT();                            // 退出临界区
            *p_err = OS_ERR_SCHED_LOCKED;
            return ((OS_SEM_CTR)0);
        }
    }

    OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();                  // 锁定调度器,使能中断
    OS_Pend((OS_PEND_DATA *)0,                              // 把任务添加到挂起表中
            (OS_PEND_OBJ  *)0,
            (OS_STATE      )OS_TASK_PEND_ON_TASK_SEM,
            (OS_TICK       )timeout);
    OS_CRITICAL_EXIT_NO_SCHED();                            // 退出临界区,不调度
    OSSched();                                              // 执行任务调度程序

    CPU_CRITICAL_ENTER();                                   // 进入临界区
    switch (OSTCBCurPtr->PendStatus) {                      // 查看等待信号量的结果
        case OS_STATUS_PEND_OK:                             // 信号量发布了
             if (p_ts != (CPU_TS *)0) {
                *p_ts                    =  OSTCBCurPtr->TS;
#if OS_CFG_TASK_PROFILE_EN > 0u
                OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS;
                if (OSTCBCurPtr->SemPendTime > OSTCBCurPtr->SemPendTimeMax) {
                    OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime;
                }
#endif
             }
             *p_err = OS_ERR_NONE;
             break;
        case OS_STATUS_PEND_ABORT:                          // 等待操作被其他任务取消了
             if (p_ts != (CPU_TS *)0) {
                *p_ts  =  OSTCBCurPtr->TS;
             }
             *p_err = OS_ERR_PEND_ABORT;                    
             break; 
        case OS_STATUS_PEND_TIMEOUT:                        // 在特定的超时时间内,信号量没有被发布
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = (CPU_TS  )0;
             }
             *p_err = OS_ERR_TIMEOUT;                       
             break;
        default:                                            // 其他情况
             *p_err = OS_ERR_STATUS_INVALID;
             break;
    }
    ctr = OSTCBCurPtr->SemCtr;
    CPU_CRITICAL_EXIT();                                    // 退出临界区
    return (ctr);
}

4.发布任务信号量使用OSTaskSemPost(),它的定义位于os_task.c中。

OS_SEM_CTR  OSTaskSemPost (OS_TCB  *p_tcb,                  // 1401行 - 1439行
                           OS_OPT   opt,                    // 发布任务信号量的方式
                           OS_ERR  *p_err)
{
    OS_SEM_CTR  ctr;
    CPU_TS      ts;

#ifdef OS_SAFETY_CRITICAL                                   // 允许进行系统安全性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_SEM_CTR)0);
    }
#endif

    ts = OS_TS_GET();                                       // 获取时间戳

#if OS_CFG_ISR_POST_DEFERRED_EN > 0u                        // 延迟发布模式
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 查看是否是在ISR中调用该函数
        OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_TASK_SIGNAL,   // 写入到中断队列中
                    (void      *)p_tcb,
                    (void      *)0,
                    (OS_MSG_SIZE)0,
                    (OS_FLAGS   )0,
                    (OS_OPT     )0,
                    (CPU_TS     )ts,
                    (OS_ERR    *)p_err);
        return ((OS_SEM_CTR)0);
    }
#endif
    ctr = OS_TaskSemPost(p_tcb,                             // 发布信号量
                         opt,
                         ts,
                         p_err);
    return (ctr);
}

发布任务信号量的方式有以下两种:
OS_OPT_POST_NONE表明发布任务信号量之后调用调度程序;
OS_OPT_POST_NO_SCHED表明在OSTaskSemPost()的末尾不会调用调度程序。

5.任务信号量做双向同步时,不能用于任务和ISR之间的同步,因为ISR不能等待信号量。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值