uC/OS-III之资源管理

1.最常用的独占共享资源和创建临界区的方法有4种:关中断、禁止任务调度、使用信号量、使用互斥型信号量。
一般推荐使用互斥信号量。
在访问数据量极少的时候,可以使用关中断的方式。
在访问数据量少且资源同步是在任务与任务之间的时候,可以使用关调度的方式。

2.关中断/开中断
(1)在使用关中断/开中断时,必须先调用宏CPU_SR_ALLOC()。它的作用是分配存储空间来存储当前CPU的中断状态。
(2)关中断/开中断属于CPU相关的函数,所以它们的定义位于cpu.h中,319行 - 320行

#define  CPU_CRITICAL_ENTER()  do { CPU_INT_DIS(); } while (0)          // 关中断
#define  CPU_CRITICAL_EXIT()   do { CPU_INT_EN();  } while (0)          // 开中断

#define  CPU_INT_DIS()         do { cpu_sr = CPU_SR_Save(); } while (0) // 保存CPU的状态,并关中断
#define  CPU_INT_EN()          do { CPU_SR_Restore(cpu_sr); } while (0) // 恢复CPU的状态

// 以下是汇编代码
CPU_SR_Save
        MRS     R0, PRIMASK                     // 保存CPU的状态到R0中--子函数返回时,R0存放返回值
        CPSID   I                               // 关闭中断
        BX      LR
CPU_SR_Restore
        MSR     PRIMASK, R0                     // 把R0的值复制到CPU的状态寄存器中--函数调用时,R0存放第一个参数
        BX      LR

(3)需要注意的是关中断/开中断是一个任务和一个中断服务程序共享变量或者数据结构的唯一方法

3.给调度器上锁/解锁
(1)给调度器上锁/解锁,可以防止两个以上的任务出现竞争。但如果没有关闭中断,一旦中断发生,即便在临界区内,中断服务程序也会立即执行。
(2)给调度器上锁使用OSSchedLock()函数实现,解锁使用OSSchedUnlock()函数实现,它们的定义位于os_core.c中。

// 调度器最多可以
void  OSSchedLock (OS_ERR  *p_err)                   // 在os_core.c中 441行 - 448行
{
    CPU_SR_ALLOC();                                  // 宏,声明存储空间,用来存储当前CPU的中断状态

#ifdef OS_SAFETY_CRITICAL                            // ???
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {       // 不允许在ISR中调用
        *p_err = OS_ERR_SCHED_LOCK_ISR;
        return;
    }
#endif

    if (OSRunning != OS_STATE_OS_RUNNING) {          // 确保操作是在运行状态
       *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }

    // OSSchedLockNestingCtr最大值为250,也就是说OSSchedLock()最多可以嵌套250次
    if (OSSchedLockNestingCtr >= (OS_NESTING_CTR)250u) {  // 预防OSSchedLockNestingCtr溢出
        *p_err = OS_ERR_LOCK_NESTING_OVF;
        return;
    }

    CPU_CRITICAL_ENTER();                            // 进入临界区
    OSSchedLockNestingCtr++;                         // 嵌套层数加1
#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u              // 允许测量调度器锁定时间
    OS_SchedLockTimeMeasStart();
#endif
    CPU_CRITICAL_EXIT();                             // 退出临界区
   *p_err = OS_ERR_NONE;
}
void  OSSchedUnlock (OS_ERR  *p_err)                 // 在os_core.c中 472行 - 517行
{
    CPU_SR_ALLOC();                                  // 宏,声明存储空间,用来存储当前CPU的中断状态

#ifdef OS_SAFETY_CRITICAL                            // ???
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {       // 不允许在ISR中调用
        *p_err = OS_ERR_SCHED_UNLOCK_ISR;
        return;
    }
#endif

    if (OSRunning != OS_STATE_OS_RUNNING) {          // 确保操作正在运行
       *p_err = OS_ERR_OS_NOT_RUNNING;
        return;
    }

    if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {// 查看调度器是否已锁定
       *p_err = OS_ERR_SCHED_NOT_LOCKED;
        return;
    }

    CPU_CRITICAL_ENTER();                            // 进入临界区
    OSSchedLockNestingCtr--;                         // 嵌套层数减1
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { // 调度器仍然锁定
    CPU_CRITICAL_EXIT();  // 退出临界区
       *p_err = OS_ERR_SCHED_LOCKED;
        return;
    }

#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u              // 允许测量任务调度的锁定时间
    OS_SchedLockTimeMeasStop();
#endif

    CPU_CRITICAL_EXIT();                             // 退出临界区
    OSSched();                                       // 执行任务调度
   *p_err = OS_ERR_NONE;
}

(3)在调度器上锁时,uC/OS-III会禁止用户进行阻塞调用。

4.信号量
(1)信号量通常分为两种:二进制信号量与计数型信号量。
(2)建议在使用信号量时,可以把信号量放入到函数中包起来。
(3)一般建议用信号量来访问IO设备,而不用它来访问存储单元;请求和释放信号量的过程是很费时的,因此在处理简单的、CPU能在很短时间内完成的操作时,使用关中断的方式更合理。
(4)信号量的数据结构类型为OS_SEM,它的定义位于os.h中。

typedef  struct  os_sem              OS_SEM;  // 631行

struct  os_sem {  // 858行 - 869行
    OS_OBJ_TYPE          Type;                              // 类型 Semaphore                                              */
    CPU_CHAR            *NamePtr;                           /* Should be set to OS_OBJ_TYPE_SEM                       */
    OS_PEND_LIST         PendList;                          /* Pointer to Semaphore Name (NUL terminated ASCII)       */
#if OS_CFG_DBG_EN > 0u
    OS_SEM              *DbgPrevPtr;
    OS_SEM              *DbgNextPtr;
    CPU_CHAR            *DbgNamePtr;
#endif
    OS_SEM_CTR           Ctr;                               /* List of tasks waiting on event flag group              */
    CPU_TS               TS;
};
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值