uos事件控制块与任务同步
Ucos为了任务之间的通讯定义了信号量,互斥性信号量,消息对象 消息队列等结构以及api,为了统一的管理这些同步,定义了一个结构叫做时间控制块OS_EVENT,如下
typedef struct os_event {
INT8U OSEventType;
void *OSEventPtr;
INT16U OSEventCnt;
OS_PRIO OSEventGrp;
OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE];
#if OS_EVENT_NAME_EN > 0u
INT8U *OSEventName;
#endif
} OS_EVENT;
OSEventType为事件类型,有信号量类型,互斥性信号量类型,消息邮箱类型,消息队列类型和未定义类型五种
OSEventPtr消息或者消息队列的指针
OSEventCnt 信号量计数器
OSEventTbl 等待任务表
OSEventGrp 等待事件的任务组
该结构我们称之为时间控制体ECB,系统中拥有的全部ECB的数量为
OS_EXT OS_EVENT OSEventTbl[OS_MAX_EVENTS];
OS_MAX_EVENTS是在系统配置文件中指定的,也就是编译时决定有几个事件控制体
每个事件控制体内部都有OSEventTbl这个数组, OS_EVENT_TBL_SIZE是一个宏定义,展开之后的定义为((OS_LOWEST_PRIO) / 8u + 1u),和系统就绪表的大小一致
那么正好和OSEventGrp合作起来,用与系统就绪表的方法类似的标识方式作为等待事件的任务标识,具体的解析请查看系统就绪表的说明文章,只介绍一点,当某个任务等待某个已经生成的特定事件的时候,就会在该事件对应的ecb中的OSEventTbl中相应的位置1,并且这个元素对应的OSEventGrp的位置也会置一,当系统在查找等待该事件的任务的时候,就可以直接通过与任务就绪表相同的方式找到等待该事件的最高优先级的任务.如下
y = OSUnMapTbl[pevent->OSEventGrp];
x = OSUnMapTbl[pevent->OSEventTbl[y]];
prio = (INT8U)((y << 3u) + x);
这是os_eventtaskready函数的实现可以看到就是直接从表中得到的等待任务的优先级.
其次是OSEventPtr,在系统初始化的时候,他并不是消息或者消息队列的指针,而是操作系统借助OSEventPtr该元素将整个事件控制块数组都连接在了一起,类似于tcb的连接,形成了一个链表,我们叫做空事件控制块链表,如下
OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl));
for (ix = 0u; ix < (OS_MAX_EVENTS - 1u); ix++) {
ix_next = ix + 1u;
pevent1 = &OSEventTbl[ix];
pevent2 = &OSEventTbl[ix_next];
pevent1->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent1->OSEventPtr = pevent2;
#if OS_EVENT_NAME_EN > 0u
pevent1->OSEventName = (INT8U *)(void *)"?";
#endif
}
pevent1 = &OSEventTbl[ix];
pevent1->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent1->OSEventPtr = (OS_EVENT *)0;
#if OS_EVENT_NAME_EN > 0u
pevent1->OSEventName = (INT8U *)(void *)"?";
#endif
OSEventFreeList = &OSEventTbl[0];
#else
OSEventFreeList = &OSEventTbl[0];
OSEventFreeList->OSEventType = OS_EVENT_TYPE_UNUSED;
OSEventFreeList->OSEventPtr = (OS_EVENT *)0;
这段代码类似于tcb初始化链接的代码,引入了一个新的全局变量OSEventFreeList代表系统空闲事件控制块的指针,连接好了之后,使用时方法如下
pevent = OSEventFreeList;
if (OSEventFreeList != (OS_EVENT *)0) {
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
创建新的事件的时候,将空事件控制链表的第一个元素拿来存放事件,链表头更新为原来的第二个元素,返回取下来的元素的ecb事件控制体的指针等待用户操作.
系统创建事件相关的函数有四个
OSMboxCreate 创建消息邮箱
OSMutexCreate 创建互斥性信号量
OSQCreate 创建qs消息队列
OSSemCreate 创建信号量
删除事件的函数也对应的有四个,
OSMboxDel 删除消息邮箱
OSMutexDel 删除互斥信号量
OSQDel 删除消息队列
OSSemDel 删除信号量
这个函数都有自己的实现,但是创建函数统一的都调用了一个函数,为
OS_EventWaitListInit(pevent);参数是可用的事件ecb指针
功能很简单,将事件结构体中的OSEventTbl和OSEventGrp清零
接下来应该讲述各个信号的操作了,但是为了更好地讲述,我们需要先来认识几个函数
OS_EventTaskWait
该函数是当一个任务请求了事件但是不能获得的时候将任务登记在时间的等待任务列表中,并把任务控制块的任务等待状态置为非就绪任务,其接受的参数是一个时间控制体的指针,代码如下
OSTCBCur->OSTCBEventPtr = pevent;
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
y = OSTCBCur->OSTCBY;
OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0u) {
OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
第一句将当前任务的tcb中的事件指针指向传入参数的ecb
二三句相当于在ecb中标识了哪个优先级的任务在等待事件
最后几句是将系统就绪表中当前任务的任务状态设置为非ready状态,此时任务被挂起进入等待任务状态,该函数主要在事件请求中调用,OSXXXPEND()
当任务获取到事件的时候就应当从挂起状态进入到就绪状态,使用的函数为
OS_EventTaskRdy,参数为事件ecb的指针
该函数实现的功能为调用这个函数的任务在任务等待ecb中清零,然后将任务就绪表中对应位置写1,标识任务已经就绪,该函数主要在事件发送过程中调用,OSXXXPOST()函数调用.代码如下
y = OSUnMapTbl[pevent->OSEventGrp];
x = OSUnMapTbl[pevent->OSEventTbl[y]];
prio = (INT8U)((y << 3u) + x);
ptcb = OSTCBPrioTbl[prio];
ptcb->OSTCBDly = 0u;
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[y] |= ptcb->OSTCBBitX;
OS_EventTaskRemove(ptcb, pevent);
可以看到,获取ecb指针之后,从ecb等待任务表中获取最高优先级的等待任务的优先级,用优先级获取tcb,在任务未挂起的情况下,将系统就绪表中的就绪标志置一,从而标识系统就绪,
综合起来看,也就是说,任务请求消息的时候可能会让自身被挂起,而任务发送消息的时候,会让消息ecb中最高优先级的等待消息任务被激活.
OS_EventTaskRemove代码为
y = ptcb->OSTCBY;
pevent->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
if (pevent->OSEventTbl[y] == 0u) {
pevent->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
}
从任务ecb中将当前最高优先级的等待任务清除掉,因为该任务已经获得事件了
有时候任务是有等待时限的,当任务等待一个事件的时候,设置了等待时限,当等待时限到达,任务会继续执行,防止因为等待事件造成任务卡死,在OSXXXPend中有这样的代码
OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */
此处将OSTCBStat设置为OS_STAT_MBOX,并设置了一个等待时间timeout,那就必然和OSTimeTick有关系,查找OSTimeTick,发现这么一段
if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_PEND_ANY;
ptcb->OSTCBStatPend = OS_STAT_PEND_TO;
} else {
ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
}
也就是说,timetick工作的时候在将OSTCBDly递减,当递减到0的时候,检测OSTCBStat,如果这是一个事件,那么ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_PEND_ANY;这句话能够让任务成为ready状态,同时OSTCBStatPend设置为OS_STAT_PEND_TO,是的任务能够在下面的调度中运行起来.
但是,这个请求并不是被删除了,而是依旧存在于任务ecb中,当系统post消息的时候,依旧会将消息给之前等待的任务.
事件的基本调度过程就是如上所说,下面将讲述如何具体的对各个信号量进行调用和调度.
uos事件控制块与任务同步的更多相关文章
- uCos-II中任务的同步与通信
任务的同步与通信 任务间的同步 在多任务合作工作过程中,操作系统要解决两个问题: 各任务间应该具有一种互斥关系,即对某些共享资源,如果一个任务正在使用,则其他任务只能等待,等到该任务释放资源后,等待任 ...
- μC/OS-II 任务的同步与通信 --- 信号量
任务间通信 系统中的多个任务在运行时,经常需要互相无冲突地访问同一个共享资源,或者需要互相支持和依赖,甚至有时还要互相加以必要的限制和制约,才保证任务的顺利运行.因此,操作系统必须具有对任务的运行进行 ...
- RT-Thread--线程间同步
线程间同步 一个线程从传感器中接收数据并且将数据写到共享内存中,同时另一个线程周期性的从共享内存中读取数据并发送去显示,下图描述了两个线程间的数据传递: 如果对共享内存的访问不是排他性的,那么各个线程 ...
- 鸿蒙内核源码分析(事件控制篇) | 任务间多对多的同步方案 | 百篇博客分析OpenHarmony源码 | v30.02
百篇博客系列篇.本篇为: v30.xx 鸿蒙内核源码分析(事件控制篇) | 任务间多对多的同步方案 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当 ...
- 开源即时通讯GGTalk 8.0发布,增加Linux客户端,支持在统信UOS、银河麒麟上运行!
GGTalk在2021年推出7.0后,经过一年多时间的开发,终于推出8.0版本,实现了Linux客户端. 这几年,信创国产化的势头越来越猛,政府事企业单位都在逐步转向使用国产OS.国产CPU.国产数据 ...
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- FFmpeg学习6:视音频同步
在上一篇文章中,视频和音频是各自独立播放的,并不同步.本文主要描述了如何以音频的播放时长为基准,将视频同步到音频上以实现视音频的同步播放的.主要有以下几个方面的内容 视音频同步的简单介绍 DTS 和 ...
- SQLServer事务同步下如何收缩日志
事务同步是SQLServer做读写分离的一种常用的方式. 随着业务数据的不断增长,数据库积攒了大量的日志,为了腾出硬盘空间,需要对数据库日志进行清理 订阅数据库的日志清理 因为订阅数据库所有的数据都来 ...
- 多线程的通信和同步(Java并发编程的艺术--笔记)
1. 线程间的通信机制 线程之间通信机制有两种: 共享内存.消息传递. 2. Java并发 Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式执行,通信的过程对于程序员来说是完全透 ...
随机推荐
- PHP 实现定时任务的几种方法
一. 简单直接不顾后果型 <?php ignore_user_abort();//关掉浏览器,PHP脚本也可以继续执行. set_time_limit(0);// 通过set_time_limi ...
- Hibernate的dynamic-insert和dynamic-update的使用
Hibernate在初始化的时候,默认按照配置为表预定义insert,delete,update,select(by id)的SQL语句放在session中,其中insert,update,selec ...
- 为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
在上两篇文章中,我们介绍了如何为Android系统的硬件编写驱动程序,包括如何在Linux内核空间实现内核驱动程序和在用户空间实现硬件抽象层接 口.实现这两者的目的是为了向更上一层提供硬件访问接口,即 ...
- 使用Theos做一个简单的Mobile Substrate Tweak
01 January 2014 Mobile Substrate和Theos Mobile Substrate是Cydia的作者Jay Freeman (@saurik)的另外一个牛X的作品,也叫Cy ...
- 转:Jmeter 用户思考时间(User think time),定时器,和代理服务器(proxy server)
在负载测试中需要考虑的的一个重要要素是思考时间(think time), 也就是在两次成功的访问请求之间的暂停时间. 有多种情形挥发导致延迟的发生: 用户需要时间阅读文字内容,或者填表,或者查找正确的 ...
- drawable文件夹详解
QVGA使用ldpi,虽然有不同尺寸,但都是120dpi左右:HVGA同理:如下图: -finger 用于触摸屏的设备 -hdpi 近似于240dpi的高级显示密度的屏幕 -mdpi ...
- PD生成oracle表名带引号解决方案
使用PowerDesigner生成数据库建表SQL脚本时,尤其是Oracle数据库时,表名一般会带引号.其实加引号是PL/SQL的规范,数据库会 严格按照“”中的名称建表,如果没有“”,会按照ORAC ...
- 第11章 类的高级特性--final
1.final变量 (1)final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值.通常,由final定义的变量为常量.例如:final double PI=3.14; final关 ...
- cookies和session的优缺点
具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案. Cookie的优缺点: 优点:极高的扩展性和可用性通过良好的编程,控制保存在cookie ...
- [转] Spring Security(01)——初体验
[转自:http://haohaoxuexi.iteye.com/blog/2154299] 首先我们为Spring Security专门建立一个Spring的配置文件,该文件就专门用来作为Sprin ...