Ucos2之互斥锁

本博客用于鄙人的每周总结,如有错误不妥之处,还望各位前辈指导。谢谢!

一、互斥锁是什么东西?

互斥锁是一种uCos2对资源保护的措施,比如任务需要访问某些资源的,但是这些资源不能同时被几个任务访问,这个时候就需要互斥锁这类的技术。互斥锁保护的资源要求,同时访问该资源的任务只能有一个,如果其他任务需要访问,则需要等待。那么程序如何实现互斥锁了?这里我列出了,使用互斥锁所需要解决的问题。

  1. 怎么创建一个互斥锁?

2、怎么查询当前资源是否可以使用?

3、如果当前任务访问被互斥锁保护的资源时,发现该资源正在被其他任务所占用,那么程序如何处理。、

4、如何长时间等待不到资源,任务该怎么办,就这样一直被挂起呢?

5、当任务访问资源结束,怎么释放互斥锁,以及让等待的任务得到互斥锁呢?

6、如果我不想保护该资源了,怎么删除一个互斥锁。

在此之前,我需要强调几点,首先我们得明白任务和TCB的关系。

二、如何创建一个互斥锁

互斥锁是和事件ECB控制块是绑定在一起的,要创建一个互斥锁,就需要创建了一个事件ECB。UCos2在初始化的时候,就创建了一个空白的ECB数组,就是为了后来的直接使用。那么我们应该访问这个数组,怎么知道数组中哪个位置是没有被使用的呢?这里uCos2使用了一个指针OSEventFreeList,专门用于标记数组中未被使用的的位置。通过这个指针我们就可以初始化自己的ECB事件控制块了。这里介绍一下ECB的结构体数据类型。

typedef struct os_event {
INT8U    OSEventType;  //事件的类型  
void    *OSEventPtr;   //主要用来存放消息邮箱或消息队列的指针                  
INT16U   OSEventCnt;   //信号量的计数器                
#if OS_LOWEST_PRIO <= 63
INT8U    OSEventGrp;  //等待任务组                  
INT8U    OSEventTbl[OS_EVENT_TBL_SIZE]; //等待任务表  
#else
INT16U   OSEventGrp;    //事件等待表,类似于任务就绪表
INT16U   OSEventTbl[OS_EVENT_TBL_SIZE]; 
#endif
#if OS_EVENT_NAME_SIZE > 1
    INT8U    OSEventName[OS_EVENT_NAME_SIZE];
#endif
} OS_EVENT;

 

那么我们创建一个互斥锁的时候,就需要对这些变量进行赋值。具体函数代码如下:

 

OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;  //更新指针,指向下一个空闲的ECB
    OS_EXIT_CRITICAL();
    pevent->OSEventType   = OS_EVENT_TYPE_MUTEX; //事件类型为互斥锁
pevent->OSEventCnt    = (INT16U)((INT16U)prio << 8) | OS_MUTEX_AVAILABLE; //设置互斥锁可用
pevent->OSEventPtr    = (void *)0; //这个在后来的操作中用用处                      
#if OS_EVENT_NAME_SIZE > 1
    pevent->OSEventName[0] = '?';  //设置名称
    pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
    OS_EventWaitListInit(pevent);  //对事件等待列表的初始化

这样我们就创建了一个互斥锁,我们对结构体的一些变量做更近一步的解释。其中比较难理解的,和后面在防止优先级翻转的问题上必不可少的一个成员OSEventCnt,这个成员为16位的数据,高低八位的数据代表不同的含义。

成员变量

功能

备注

OSEventCnt

高八位:在后面的优先级翻转问题中,会详细解释。

 

低八位:用于表示当前互斥锁的状态,当数据为0xFF时,表示该互斥锁可以访问;如果为其他值则代表现在占用该互斥锁的任务的优先级,也就是当任务占用互斥锁的时候,会把本身的优先级存储在低八位。

 

 

 

三、如何去查询一个互斥锁是否可用

这里涉及到两个函数,两个函数都是去访问互斥锁的资源,但是两个函数的作用是不一样。其中BOOLEAN  OSMutexAccept (OS_EVENT *pevent, INT8U *perr)函数是一个非堵塞的函数,当访问的互斥锁不能够使用的时候,会直接返回。不会做其他处理,如果访问的互斥锁可以直接使用,则进行一些必要的操作。判断的方式就是我们上面介绍的OSEventCnt低八位是否为0xFF。另一个函数是void  OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr),也是访问互斥锁的函数,但是该函数是堵塞的。就是在互斥锁不能够访问的时候,会将该任务挂起,等待互斥锁的释放。这里就涉及到很多的问题:

  1. 怎么把任务挂起。
  2. 任务怎么知道自己能够访问互斥锁了,
  3. 如果长时间等不到互斥锁,有什么机制来防止这种情况。

如何挂起任务,大致需要两个步骤,一个是将任务在事件的等待列表中对应的位置置位,二来就是把自己在就绪表中的状态设置为非就绪态即可。为了防止长时间等不到互斥锁,函数的输入参数中的timeout用于设置等待互斥锁的时间,如果在等待的这段时间中,互斥锁都无法释放,那么任务就会停止等待该互斥锁,转为就绪态。那么任务怎么知道自己等待的互斥锁可以访问的呢?占用互斥锁的任务,在访问结束之后,会释放互斥锁,具体的操作和上面挂起一个互斥锁的操作是相反的,一是要在事件等待的列表中,把优先级最高的任务在列表中清零,然后把该任务在就绪表中的设置为就绪态,就可以参数OS的任务调度。等到自己的时间片,任务就可以执行了,访问等待的互斥锁所保护的资源了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值