ucosIII 共享资源(信号量、互斥信号量)

共享资源:

变量(静态或全局变量)、数据结构体、RAM表格、I/O设备等。OS在使用一些资源时候,例如IO设备打印机,当任务1在使用打印机时候必须保证资源独享,避免其他任务修改打印内容导致出错,因此需要有资源共享机制。

一般推荐使用互斥信号量对共享资源实现保护

独占资源和创建临界区方法表

方法优点何时使用
开关中断能很快地结束访问共享资源,不推荐,会导致中断延迟访问共享资源时间小于中断关闭时间
锁调度器不推荐,有悖ucos任务切换访问共享资源时间大于中断关闭时间,给调度器上锁时间短
信号量信号量可能会造出优先级反转。然而,信号量方式的执行时间少于互斥信号量 方式所有的任务可以无限期等待对共享资源的访问
互斥信号量推荐使用这种方法访问共享资源,有内置的优先级,时间较久当任务要访问的共享资源有截止时间

只有开关中断才能任务和中断程序共享资源。其它只能用于任务相关的资源共享。

关/开中断

和CPU 相关的操作,其相关代码被放在与CPU相关的文件中(见CPU.H)。uC/OS-III 中与CPU相关的模块叫做uC/CPU。每种架构的CPU 都需要设置相适应的uC/CPU 文件。

API注释
CPU_SR_ALLOC()分配存储空间存储当前cpu的中断状态
CPU_CRITICAL_ENTER()关全局中断
CPU_CRITICAL_EXIT()开全局中断,恢复局部变量中存储的cpu中断状态

只有这种方法才能任务和中断程序共享资源。只要关中断的时间不比系统本身的关中断时间长,就不会影响到系统的中断延时。

锁调度器

如果任务不需要和ISR 共享资源,就可以通过锁调度器来访问共享资源。
实际上就是禁止任务调度已达到资源的独占

API注释
OSSchedLock()锁调度
OSSchedUnlock()开调度

注意,只有调度器被锁,中断是使能的,如果在处理临界段时中断发生,ISR程序就会被执行。在ISR 的末尾,uC/OS-III会返回原任务(即使ISR中有高优先级任务被就绪)。

支持嵌套250 级。当OSSchedUnlock()与OSSchedLock()被调用的次数相同时调度器才被锁调度器影响了抢占式内核的初衷,内核行为实际与不可剥夺的内核已经是一样的了。

信号量

一种上锁机制,代码需要获取对应的钥匙才能访问共享资源(继续执行),我的理解是实际上只是对访问共享资源区的代码段进行上锁,如果没有获取到钥匙(信号量)则等待无法继续执行,只有别的任务施放了信号量之后才能继续执行下去。

二进制信号量和计数型信号量:

二进制信号量只能取0和1两个值,计数型信号量的信号量值大于1,计数型信号量的范围由OS_SEM_CTR决定,OS_SEM_CTR可以为8位,16位和32位,取值范围分别为:0~255,0~65535和0~4294967295。

二值信号量用于那些一次只能一个任务使用的资源,比如I/O设备,打印机计,数型信号量用于某些资源可以同时被几个任务所使用,比如一个缓存池有10个缓存块,那么同时最多可以支持10个任务来使用内存池。

应用中可以使用任意数量的信号量,但是一般用于IO保护,很多情况下,访问一个简短的共享资源时不推荐使用信号量,请求和释放信号量会消耗CPU时间。

API注释
OSSemCreate()创建一个信号量
OSSemDel()删除一个信号量
OSSemPend()等待一个信号量
OSSemPendAbort()取消等待
OSSemPoset()释放一个信号量
OSSemSet()强制设置信号量值
OS_SEM信号量类型

定义一个信号量

OS_SEM XXX 

创建一个信号量

void  OSSemCreate (OS_SEM *p_sem, //信号量结构体,其中OS_SEM_CTR Ctr表示信号量的值
                   CPU_CHAR *p_name,//名字
                   OS_SEM_CTR cnt,   //信号量初始值
                   OS_ERR *p_err)

删除一个信号量

OS_OBJ_QTY  OSSemDel(OS_SEM *p_sem,
                     OS_OPT opt, 
     //1.NO_PEND 仅当没有信号请求的时候才删除
     //2.ALWAYS 直接删除,不管有没有信号请求
                     OS_ERR *p_err)

请求/等待一个信号量

OS_SEM_CTR  OSSemPend(OS_SEM *p_sem, 
                      OS_TICK timeout,//等待的时间,如果为0:一直等待下去
                      OS_OPT opt,
         //1.暂时无效直接挂起 OS_OPT_PEND_BLOCKING
         //2.无效直接返回OS_OPT_PEND_NON_BLOCKING
                      CPU_TS *p_ts,//时间戳:记录接受信号量的时刻,0或者null则不需要时间戳。
                      OS_ERR *p_err)

取消等待

OS_OBJ_QTY  OSSemPendAbort(OS_SEM *p_sem,
                           OS_OPT opt,
             //1. 仅终止等待该信号量的最高优先级任务
             //2. 中止所有的等待该信号量的任务
             //3. 禁止任务调度
                           OS_ERR *p_err)

释放一个信号量

OS_SEM_CTR OSSemPost(OS_SEM *p_sem,
                     OS_OPT opt,
              //1. 仅发送给等待该信号量的最高优先级任务
              //2. 发送给所有的等待该信号量的任务
              //3. 禁止任务调度
                     OS_ERR *p_err)

步骤:
先定义OS_SEM
Create创建信号量
OSSemPend等待信号量
OSSemPost释放信号量

互斥信号量

使用信号量访问共享资源会有优先级反转问题:高优先级A任务执行访问共享资源的时候被迫等待低优先级任务D释放信号量,此时会发生任务切换到低优先级。如果此时又有高一级的任务B中断了D的任务,虽然B任务比A任务优先级更低,也会发生任务调度。使得高优先级任务A实际上被拉到占用信号量的低优先级任务D同一优先级别,违背了实时RTOS。

互斥信号量实际解决方法就是,将低优先级任务D的优先级临时提升至任务A同一优先级,等信号量释放后,再将任务D的优先级恢复,这样任务切换只在这两个任务之间执行(如果有比A更高的还是会切换)。

API注释
OSMutexCreate()创建一个互斥信号量
OSMutexDel()删除一个互斥信号量
OSMutexPend()等待一个互斥信号量
OSMutexPendAbort()取消等待信号量
OSMutexPost()释放一个互斥信号量

创建互斥信号量

void  OSMutexCreate(OS_MUTEX  *p_mutex,//指向互斥信号量的控制块
                    CPU_CHAR  *p_name, //互斥信号量名字
                    OS_ERR    *p_err)//调用此函数后返回的错误码

请求/等待互斥信号量

void  OSMutexPend(OS_MUTEX  *p_mutex, //指向互斥信号量的控制块
                  OS_TICK timeout,//指定等待互斥信号量的超时节拍,超时继续执行,0位一直等待
                  OS_OPT opt,//是否阻塞
             //OS_OPT_PEND_BLOCKING无效挂起
             //OS_OPT_PEND_NON_BLOCKING无效直接返回
                  CPU_TS *p_ts,//时间戳
                  OS_ERR *p_err)//错误码

释放互斥信号量

void  OSMutexPost(OS_MUTEX *p_mutex,//指向互斥信号量

                  OS_OPT opt,//指定是否进行任务调度操作
    //OS_OPT_POST_NONE不指定特定的选项
    //OS_OPT_POST_NO_SCHED 禁止在本函数内执行任务调度

                  OS_ERR *p_err)//错误码

步骤:
先定义OS_MUTEX xxxx
Create创建信号量
OSMutexPend等待信号量
OSMutexPost释放信号量

死锁:

任务1需要的资源要等到任务2释放,任务2的资源需要等待任务1释放,造成死锁。
(1)假定任务T1 所等待的事情发生,任务1被执行。
(2)任务T1 申请M1。(mutex 1)
(3)任务T1 访问资源R1。
(4)中断发生,中断中使能了任务T2。由于任务T2 的优先级高于任务T1,CPU 切换到任务T2。
(5)该中断即是任务T2 所等待的事件。
(6)任务T2 申请M2 并占用资源R2。
(7)任务T2 申请M1,但是M1 已被任务T1 占用。任务T2
被挂起。
(8)uC/OS-III 切换到任务T1。
(9)此时任务T1 申请M2,但是M2 已经被任务T2 占用。

此时,两个任务互相等待,这就算死锁。

用以下方式防止死锁:
1)同一个时间不要申请多于一个mutex
2)不要直接地申请mutex(该申请放到器件驱动中和可重入函数中)
3)在处理之前先获得全部所需要的mutex
4)任务间以同样的顺序申请资源

当申请信号量或mutex 时允许设置时间期限,这样能防止死锁,但是同样的死锁可能稍后再次出现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值