ucos实时操作系统学习笔记——任务间通信(消息)
ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox。为什么有了queue机制还要用mbox呢,只要设置queue的msg只有一个不就行了?其实很简单,就是为了节约资源,因为使用queue的话需要专门描述queue的机构体os_q,同时需要分配一段内存用来存放msg,而如果直接使用mbox机制的话,就好多了,节约。。。。。
首先从mbox的创建开始,mbox创建的函数是OSMboxCreate ,简化代码如下:
OS_EVENT *OSMboxCreate (void *pmsg)
{
OS_EVENT *pevent; if (OSIntNesting > ) { /* See if called from ISR ... */
return ((OS_EVENT *)); /* ... can't CREATE from an ISR */
}
OS_ENTER_CRITICAL();
pevent = OSEventFreeList; /* Get next free event control block */
if (OSEventFreeList != (OS_EVENT *)) { /* See if pool of free ECB pool was empty */
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if (pevent != (OS_EVENT *)) {
pevent->OSEventType = OS_EVENT_TYPE_MBOX;
pevent->OSEventCnt = ;
pevent->OSEventPtr = pmsg; /* Deposit message in event control block */
OS_EventWaitListInit(pevent);
}
return (pevent); /* Return pointer to event control block */
}
mbox使用同样使用event机制,它与sem的不同之处在于sem使用event中OSEventCnt变量存放信号量,而mbox使用OSEventPtr存放创建时候的msg地址,可以对比sem的create代码,两者的create代码如此相似。
void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
{
void *pmsg; if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
*perr = OS_ERR_EVENT_TYPE;
return ((void *));
}
if (OSIntNesting > ) { /* See if called from ISR ... */
*perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
return ((void *));
}
if (OSLockNesting > ) { /* See if called with scheduler locked ... */
*perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
return ((void *));
}
OS_ENTER_CRITICAL();
pmsg = pevent->OSEventPtr;
if (pmsg != (void *)) { /* See if there is already a message */
pevent->OSEventPtr = (void *); /* Clear the mailbox */
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return (pmsg); /* Return the message received (or NULL) */
}
OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next highest priority task ready to run */
OS_ENTER_CRITICAL();
switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
case OS_STAT_PEND_OK:
pmsg = OSTCBCur->OSTCBMsg;
*perr = OS_ERR_NONE;
break; case OS_STAT_PEND_ABORT:
pmsg = (void *);
*perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
break; case OS_STAT_PEND_TO:
default:
OS_EventTaskRemove(OSTCBCur, pevent);
pmsg = (void *);
*perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */
break;
}
OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
OSTCBCur->OSTCBEventPtr = (OS_EVENT *); /* Clear event pointers */
OSTCBCur->OSTCBMsg = (void *); /* Clear received message */
OS_EXIT_CRITICAL();
return (pmsg); /* Return received message */
}
因为好于其他的机制代码对比,所以将整个代码贴出来,其实主要的差别在黄色部分,因为在创建msg的时候,或者在post msg的时候,会将msg放到OSEventPtr,所以直接从中取出msg,判断当前的msg是否存在,如果存在的话就会将msg返回并且对msgbox即OSEventPtr清0操作;如果msg没有则直接将当前任务挂起处于event的等待列表中,进行任务调度也就是黄色部分下面的处理过程,不做过多的赘述。
INT8U OSMboxPost (OS_EVENT *pevent, void *pmsg)
{
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
return (OS_ERR_EVENT_TYPE);
}
OS_ENTER_CRITICAL();
(1)====================================================================================================
if (pevent->OSEventGrp != ) { /* See if any task pending on mailbox */
/* Ready HPT waiting on event */
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
OS_EXIT_CRITICAL();
OS_Sched(); /* Find highest priority task ready to run */
return (OS_ERR_NONE);
}
(2)====================================================================================================
if (pevent->OSEventPtr != (void *)) { /* Make sure mailbox doesn't already have a msg */
OS_EXIT_CRITICAL();
return (OS_ERR_MBOX_FULL);
}
pevent->OSEventPtr = pmsg; /* Place message in mailbox */
OS_EXIT_CRITICAL();
return (OS_ERR_NONE);
(3)====================================================================================================
}
mbox的post函数代码如上所示,其实处理过程和sem等类似,post其实就是填充的功能,首先判断有没有在等待当前event的任务存在,如果有的话直接将msg等交给等待任务,如果没有则进入到第三部分,判断当前的OSEventPtr中是否有msg,如果有表示没有任务从中取出msg,这时会返回错误,如果OSEventPtr中没有msg,则将msg放到OSEventPtr中,等待任务从中取出。
通过学习sem,mutex,queue以及mbox的内核实现可以大体的了解操作系统任务间的通信机制是如何实现的,也可以和其他的操作系统作对别,通过简单的内核实现取理解复杂的操作系统该部分的实现机制,比如所Linux操作系统,这是一个很好的学习方法。下面简单总结一下这四中通信机制的功能:
1. 信号量:信号量其实就是一种通过数字大小来实现限制资源使用的一种机制,设置信号量其实就是设置资源最大可以允许多少个任务同时访问同一个资源,通过信号量pend和post操作即信号量变量的加减实现任务控制,当特殊情况,只有一个信号量的时候就有点互斥的意思。
2. 互斥锁:互斥锁就是同一时间只有一个任务可以占有资源,当有其他任务要访问资源的时候就会将这个任务挂起,放到event的等待列表中,当占有资源的任务释放掉锁的时候,等待任务才可以占有资源并且上锁,为了防止优先级的翻转,使用了优先级继承的机制,就是把占有资源的任务的优先级提升一下比要使用资源的任务的优先级高。
3. 队列:队列就是取一段内存用于存放消息,这个消息是一个地址,真正的消息内容是存放在这个地址中,这样的话可以就可以实现真正的任务间通信,将数据从一个任务传到另一个任务,而不像信号量和互斥锁一下仅仅是一个限制作用。队列使用要注意,如果多个任务在等待不同的消息的话,有可能会出现不同任务获得了不是自己想要的信息并且将消息从队列中去除掉了,所以使用的时候需要注意。
4. 消息:消息其实是队列的一种特殊情况,为了节省资源,之前也有讲到,如果消息数量一定的话同一时间只有一个消息使用,那么采用消息机制更简单,同样实现了数据的传输功能。消息的使用也同样要注意,pend和post的使用,因为如果有多个任务同时使用的话,就会存在是否是当前任务想要的信息,如果不是的话有可能把别的任务的消息给去处并释放掉了,所以使用时需要注意。
ucos实时操作系统学习笔记——任务间通信(消息)的更多相关文章
- ucos实时操作系统学习笔记——任务间通信(信号量)
ucos实时操作系统的任务间通信有好多种,本人主要学习了sem, mutex, queue, messagebox这四种.系统内核代码中,这几种任务间通信机制的实现机制相似,接下来记录一下本人对核心代 ...
- ucos实时操作系统学习笔记——任务间通信(队列)
ucos操作系统中的queue机制同样使用了event机制来实现,其实和前面的sem,mutex实现类似,所不同的是对sem而言,任务想获得信号量,对mutex而言,任务想获得的是互斥锁.任务间通信的 ...
- ucos实时操作系统学习笔记——任务间通信(互斥锁)
想讲一下ucos任务间通信中的mutex,感觉其设计挺巧妙,同sem一样使用的是event机制实现的,代码不每一行都分析,因为讲的没邵贝贝老师清楚,主要讲一下mutex的内核是如何实现的.可以理解互斥 ...
- ucos实时操作系统学习笔记——操作系统在STM32的移植
使用ucos实时操作系统是在上学的时候,导师科研项目中.那时候就是网上找到操作系统移植教程以及应用教程依葫芦画瓢,功能实现也就罢了,没有很深入的去研究过这个东西.后来工作了,闲来无聊就研究了一下这个只 ...
- ucos实时操作系统学习笔记——内核结构和任务创建
对于ucos实时操作系统,邵贝贝的那本书已经写得很详细了,我因为之前不深的研究过ucos,所以在这里做一个笔记,写一些个人对该操作系统的理解,仅仅是个人理解,如果有人看到这边随笔有不对的地方,望给我指 ...
- RTX51 Tiny实时操作系统学习笔记—初识RTX51 Tiny
一,RTX51 Tiny简单介绍 RTX51 Tiny是一种实时操作系统(RTOS),能够用它来建立多个任务(函数)同一时候运行的应用(从宏观上看是同一时候运行的,但从微观上看,还是独立运行的 ...
- 操作系统学习笔记----进程/线程模型----Coursera课程笔记
操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进 ...
- 操作系统学习笔记5 | 用户级线程 && 内核级线程
在上一部分中,我们了解到操作系统实现多进程图像需要组织.切换.考虑进程之间的影响,组织就是用PCB的队列实现,用到了一些简单的数据结构知识.而本部分重点就是进程之间的切换. 参考资料: 课程:哈工大操 ...
- 深挖计算机基础:趣谈Linux操作系统学习笔记
参考极客时间专栏<趣谈Linux操作系统>学习笔记 核心原理篇:内存管理 趣谈Linux操作系统学习笔记:第二十讲 趣谈Linux操作系统学习笔记:第二十一讲 趣谈Linux操作系统学习笔 ...
随机推荐
- 【.net 深呼吸】细说CodeDom(5):类型成员
前文中,老周已经厚着脸皮介绍了类型的声明,类型里面包含的自然就是类型成员了,故,顺着这个思路,今天咱们就了解一下如何向类型添加成员. 咱们都知道,常见的类型成员,比如字段.属性.方法.事件.表示代码成 ...
- jQuery之ajax实现篇
jQuery的ajax方法非常好用,这么好的东西,你想拥有一个属于自己的ajax么?接下来,我们来自己做一个简单的ajax吧. 实现功能 由于jq中的ajax方法是用了内置的deferred模块,是P ...
- C语言 · Torry的困惑(基本型)
问题描述 Torry从小喜爱数学.一天,老师告诉他,像2.3.5.7--这样的数叫做质数.Torry突然想到一个问题,前10.100.1000.10000--个质数的乘积是多少呢?他把这个问题告诉老师 ...
- hadoop 2.7.3本地环境运行官方wordcount
hadoop 2.7.3本地环境运行官方wordcount 基本环境: 系统:win7 虚机环境:virtualBox 虚机:centos 7 hadoop版本:2.7.3 本次先以独立模式(本地模式 ...
- C#多线程之线程同步篇2
在上一篇C#多线程之线程同步篇1中,我们主要学习了执行基本的原子操作.使用Mutex构造以及SemaphoreSlim构造,在这一篇中我们主要学习如何使用AutoResetEvent构造.Manual ...
- 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...
- ABP领域层
1.实体Entites 1.1 概念 实体是DDD(领域驱动设计)的核心概念之一. 实体是具有唯一标识的ID且存储在数据库总.实体通常被映射成数据库中的一个表. 在ABP中,实体继承自Entity类. ...
- trigger事件模拟
事件模拟trigger 在操作DOM元素中,大多数事件都是用户必须操作才会触发事件,但有时,需要模拟用户的操作,来达到效果. 需求:页面初始化时触发搜索事件并获取input控件值,并打印输出(效果图如 ...
- git多账号登录问题
作者:白狼 出处:http://www.manks.top/git-multiply-accounts.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文 ...
- MySQL Workbench建表时 PK NN UQ BIN UN ZF AI 的含义
[转自网络]https://my.oschina.net/cers/blog/292191 PK Belongs to primary key 作为主键 NN Not Null 非空 UQ Uniqu ...