嵌入式实时操作系统ucos/ii 原理与应用(四)

第五章 任务的同步与通信

一个完善的多任务操作系统,必须具有完备的同步和通信机制。

5.1 任务的同步和事件

5.1.1 任务间的同步

    直接制约关系:源于任务之间的合作

间接制约关系:源于对资源的共享

多任务合作过程中,处理的问题:

各任务间应该具有一种互斥关系,即对于某个共享资源,如果一个任务正在使用,则其他任务只能等待,等待该任务释放该资源后,等待的任务才能使用。

相关的任务在执行中要有先后次序,一个任务要等其伙伴发来通知,或建立了某种条件后才能继续执行,否则只能等待。(任务间的同步

5.1.2 事件

信息量邮箱(消息邮箱)消息队列这些中间环节统一被称为“事件”。

两任务使用事件进行通信的过程:


1.      信号量

信号量是一类事件,给共享资源设立的标志,标识该共享资源的被占用情况。

互斥型信号量是一个二值信号量,可以实现共享资源的独占式占用;

计数式的信号叫做信号量

两任务使用信号量进行通信:

 

            任务1先获得信号量并使用共享资源,而任务2只能等待信号量


        任务1释放信号量后,任务2方可获得信号量并使用共享资源


   给等待信号量的任务设置一个等待时限,就不会出现死机现象。

 

2.      消息邮箱

任务与任务之间通过一个数据(消息)的方式进行通信。

消息邮箱可传递一个消息,也可定义一个指针数组

两任务使用消息邮箱进行通信:


3.      消息队列

任务可以通过传递指针数组指针来传递多个消息,传递多个消息的数据结构叫做消息队列。


5.2 事件控制块及事件处理函数

5.2.1 事件控制块的结构

    1.  等待任务列表

作为功能完善的事件,对等待任务要有两方面的管理:

要对等待事件的所有任务进行记录并排序;

应该允许等待任务有一个等待时限,即当等待任务认为等不及时可以退出对事件的请求。

等待任务表:数组OSEventTbl[],以任务优先级为顺序为每个任务分配二进制位。

变量OSEventGrp标识等待任务表中的任务组。

2.  事件控制块的结构

    事件控制块ECB的数据结构来描述事件。

5.2.2 操作事件控制块的函数

4个函数对事件控制块进行基本操作。

1.      事件控制块的初始化函数

void OS_EventWaitListInit(OS_EVENT*prevent);

在任务调用函数OS×××Create()创建事件时被函数OS×××Create()所调用

2.      使一个任务进入等待状态的函数

void OS_EventTaskWait (OS_EVENT*prevent);

在任务调用函数OS×××Pend()请求一个事件时被函数OS×××Pend()所调用

3.      使一个正在等待的任务进入就绪状态的函数

void OS_EventTaskRdy (OS_EVENT *prevent,coid *msg, INT8U msk);

在任务调用函数OS×××Post ()发送一个事件时被函数OS×××Post()所调用

4.      使一个等待超时的任务进入就绪状态的函数

void OS_EventTO (OS_EVENT *prevent);

在任务调用函数OS×××Pend()请求一个事件时被函数OS×××Pend()所调用

 

5.2.3 空事件控制块链表


5.3 信号量及其操作

5.3.1 信号量

    当事件控制块成员OSEventType的值被设置为OS_EVENT_TYPE_SEM时,描述的是一个信号量,信号量由信号量计数器OSEventCnt和等待任务表OSEventTbl[]组成。

5.3.2 信号量的操作

1. 创建信号量

    OS_EVENT*OSSemCreate(INT16U cnt);

2. 请求信号量

void OSSemPend(OS_EVENT *prevent,INT16U timeout, INT8U *err);

当任务超过timeout时,可以结束等待状态而进入就绪状态,timeout = 0时,任务等待时间为无限长。

当任务请求信号量 时,如果希望在信号量无效时准许任务不进入等待状态而继续运行,则不调用函数OSSemPend(),而是调用函数OSSemAccept()来请求信号量。

INT16U OSSemAccept(OS_ECENT *prevent);

3. 发送信号量

    INT8UOSSemPost(OS_EVENT *prevent);

4. 删除信号量

OS_ECENT *OSSemDel(OS_EVENT*prevent, INT8U opt, INT8U *err);

opt用来指明信号的删除条件,如果为OS_DEL_NO_PEND,则当等待任务表中已没有等待任务时才删除信号量;如果为OS_DEL_ALWAYS,则在等待任务表中无论是否有等待任务都立即删除信号量。

只能在任务中删除信号量,而不能在中断服务程序中删除。

5. 查询信号量的状态

INT8U OSSemQuery(OS_EVENT*prevent, OS_SEM_DATA *pdata);

在调用函数时,须定义一个OS_SEM_DATA结构类型的变量

5.4 互斥型信号量和任务优先级反转

    互斥型信号时一个二值信号,它可以使任务以独占的方式使用资源。

5.4.1 任务优先级的反转现象

当任务以独占的方式使用共享资源时,会出现低优先级任务先于高优先级任务而被运行的现象,这就是任务优先级的反转。


反转现象原因:一个优先级较低的任务在获得了信号量使用共享资源期间,被具有较高优先级的任务所打断而不能释放信号量,从而使正在等待这个信号量的更高级别的任务因得不到信号量而被迫处于等待状态,在这个等待期间,就让级别低于它而高于占据信号量的任务的任务先运行了。

使用信号量的任务是否能够运行受任务的优先级别是否占用信号量两个条件约束,而信号量的约束高于优先级别的约束

解决办法:使获得信号量任务的优先级别在使用共享资源期间暂时提升到所有任务最高级别的高一个级别上,以使该任务不被其他任务所打断,从而能尽快地使用完共享资源并释放信号量,然后在释放信号量之后,再恢复该任务原来的优先级别。

5.4.2 互斥型信号量

1. 创建互斥型信号量

   OS_EVENT *OSMtexCreate(INT8U prio, INT8U *err);

2. 请求互斥型信号量

   void OSMutexPend(OS_EVENT *prevent, INT16U timeout, INT8U *err);

3. 发送互斥型信号量

   INT8U OSMutexPost(OS_EVENT *prevent);

4. 获取互斥型信号量的当前状态

   INT8U OSMutexQuery(OS_EVENT *prevent, OS_MUTEX_DATA *pdata);

5. 删除互斥型信号量

   OS_EVENT *OSMutexDel(OS_EVENT *prevent, INT8U opt, INT8U *err);

5.5 消息邮箱及其操作

5.5.1 消息邮箱

    当事件控制块成员OSEventType的值被设置为OS_EVENT_TYPE_MBOX时,描述的是一个消息邮箱,消息邮箱通过在两个需要通信的任务之间传递数据缓冲区指针来进行通信。

5.5.2 消息邮箱的操作

1. 创建消息邮箱

   OS_EVENT *OSMboxCreate(void *msg);

2. 向消息邮箱发送消息

   INT8U OSMboxPost(OS_EVENT *prevent, void *msg);

3. 请求消息邮箱

   INT8U OSMboxPend(OS_EVENT *prevent, INT16U timeout, INT8U *err);

4. 查询邮箱的状态

   INT8U OSMboxQuery(OS_EVENT *prevent, OS_MOX_DATA *pdata);

5. 删除邮箱

   OS_EVENT *OSMoxDel(OS_EVENT *prevent, INT8U opt, INT8U *err);

 

5.6 消息队列及其操作

5.6.1 消息队列

当事件控制块成员OSEventType的值被设置为OS_EVENT_TYPE_Q时,描述的是一个消息队列。

1.      消息指针数组

消息队列的数据结构:


消息指针数组:


2.      队列控制块


5.6.2 消息队列的操作

1. 创建消息队列

   OS_EVENT OSQCreate(void * *start, INT16U size);

2. 请求消息队列

   INT8U OSQPend(OS_EVENT *prevent, INT16U timeout, INT8U *err);

3. 向消息队列发送消息

   INT8U OSQPost(OS_EVENT *prevent, void *msg);先进先出

    INT8U OSQPostFront(OS_EVENT *prevent, void *msg);后进先出

   INT8U OSQPostOpt(OS_EVENT *prevent, void *msg, INT8U opt);广播

4. 清空消息队列

   INT8U OSQFlush(OS_EVENT *prevent);

5. 删除消息队列

   OS_EVENT *OSQDel(OS_EVENT *prevent);

6. 查询消息队列

   INT8U OSQQuery(OS_EVENT *prevent, OS_Q_DATA *pdata);

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值