ucos实时操作系统的任务间通信有好多种,本人主要学习了sem, mutex, queue, messagebox这四种。系统内核代码中,这几种任务间通信机制的实现机制相似,接下来记录一下本人对核心代码的学习心得,供以后回来看看,不过比较遗憾的是没有仔细学习扩展代码的功能实现部分。ucos操作系统的内核代码实现相对简单,但是对理解其他操作系统内核相同功能有帮助。

ucos的任务间通信机制主要是基于event实现的,其实理解这个event不用翻译成中文事件,就叫event感觉还更容易接收。下面是操作系统event的的数据结构:

typedef struct os_event {
INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_xxxx) */
void *OSEventPtr; /* Pointer to message or queue structure */
INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */
OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
} OS_EVENT;

上面的event是实现sem, mutex, queue, messagebox等必不可少的结构,其实该结构相对简单,主要包括OSEventType用于记录当前event是前面四种机制中的哪一种;OSEventPtr是一个指针用于指向messagebox和queue要传递的内容的地址;OSEventCnt对于sem来说,是一个计数值,而对于mutex来说则是记录任务优先级的一个变量;OSEventGrp和OSEventTbl和前面讲过的OSRdyGrp和OSRdyTbl的类似,主要记录有哪些任务在等待当前event的。对于上面四种机制的实现,首先需要创建一个event才可以实现各自的功能,比如说OSSemCreate,OSMutexCreate等。

ucos的sem主要的功能是对资源使用的一种限制,当信号量的值设置n就代表允许n个任务可以对当前资源进行使用,如果资源被n个任务占用,第n+1个任务要使用该资源时,需要等待前面n个任务中有1个或者多个释放对资源的使用权。sem的具体功能就是OSSemCreate,OSSemPend,OSSemPost等这三个函数实现的,下面将具体分析一下这三个函数。

对sem来说,首先需要创建一个event结构,然后设置这个sem event允许几个任务可以同时使用,具体函数OSSemCreate首先如下:

OS_EVENT  *OSSemCreate (INT16U cnt)
{
OS_EVENT *pevent; if (OSIntNesting > 0u) { /* 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 *)) { /* Get an event control block */
pevent->OSEventType = OS_EVENT_TYPE_SEM;
pevent->OSEventCnt = cnt; /* Set semaphore value */
pevent->OSEventPtr = (void *); /* Unlink from ECB free list */
OS_EventWaitListInit(pevent); /* Initialize to 'nobody waiting' on sem. */
}
return (pevent);
}

上面提到的四种任务间通信机制不允许在中断中创建,所以OSSemCreate首先判断当前创建过程是不是在中断中,也就是判断OSIntNesting是否大于0,有全局变量OSEventFreeList记录当前操作系统通还有多少个free的event在列表中,OSSemCreate从free list中取一个event机构,然后OSEventFreeList指向下一个未被使用的event,然后设置OSEventType和OSEventFreeListCnt,cnt是有create函数带入的参数,有使用该函数的程序员自己设定,sem不使用OSEventPtr变量,因为是指针,所以设置为0,之后初始化event的event group和 event table,表示当前没有任务等待创建的sem,返回event结构的地址,给之后讲的pend和post使用。

其次,就要讲到sem机制post和pend的两个操作了,这两个操作是成对使用的,简单点讲pend主要功能是检查create的event中的OSEventCnt是否大于0,如果大于0,说明需要保护的资源还允许任务使用,这时候只需要将OSEventCnt减1操作,表示又有一个任务占用了资源的使用权;如果OSEventCnt不大于0,则说明任务可以使用的资源的权限已经达到上限,这时候就要把要使用的该资源的任务挂起(1),让其处于等待状态,并把任务放到event的event group和event table中,处于等待状态的任务只能等其他任务释放对资源的使用权之后才可以继续运行。post的主要功能是要释放被占用的资源的使用权,其操作首先会检查当前event的group和table中有没有在等待当前event的任务存在,如果有使用权直接转给等待的任务(1),不需要对OSEventCnt加操作,如果没有等待当前event的任务,则只需要将OSEventCnt加1操作,说明资源的可使用权又大了一个。接下来我们看一下具体pend和post的代码具体流程。

void  OSSemPend (OS_EVENT  *pevent,
INT32U timeout,
INT8U *perr)
{
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
*perr = OS_ERR_EVENT_TYPE;
return;
}
if (OSIntNesting > 0u) { /* See if called from ISR ... */
*perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
return;
}
OS_ENTER_CRITICAL();
(1)===================================================================================================
if (pevent->OSEventCnt > 0u) { /* If sem. is positive, resource available ... */
pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return;
}
(2)===================================================================================================
/* Otherwise, must wait until event occurs */
OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next highest priority task ready */
OS_ENTER_CRITICAL();
switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
case OS_STAT_PEND_OK:
*perr = OS_ERR_NONE;
break; case OS_STAT_PEND_ABORT:
*perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
break; case OS_STAT_PEND_TO:
default:
OS_EventTaskRemove(OSTCBCur, pevent);
*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 */
OS_EXIT_CRITICAL();
(3)=====================================================================================================
}

OSSemPend函数首先判断当前的任务操作是否是一个sem event;然后判断是否中断中,如果是则返回错误;之后检查该sem event的资源限号量是否大于0,如果是则进行减操作表示信号量被一个任务占用,如果不大于0,说明对改event来说,已经没有信号量供使用需要的操作是挂起当前任务,并调用任务切换函数,在上面的代码中在OS_Sched()上面的四步操作是挂起任务操作,直到有可以使用的信号量再次执行任务切换时,会切换到当前任务继续从OS_Sched开始执行,可以看出下面的操作是从event的等待group和table中删除该任务,并且改变任务的状态为OS_STAT_RDY。当然任务的还有statpend状态,在此不做详细介绍。

INT8U  OSSemPost (OS_EVENT *pevent)
{
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
return (OS_ERR_EVENT_TYPE);
}
OS_ENTER_CRITICAL();
(1)=====================================================================================================
if (pevent->OSEventGrp != 0u) { /* See if any task waiting for semaphore */
/* Ready HPT waiting on event */
(void)OS_EventTaskRdy(pevent, (void *), OS_STAT_SEM, OS_STAT_PEND_OK);
OS_EXIT_CRITICAL();
OS_Sched(); /* Find HPT ready to run */
return (OS_ERR_NONE);
}
(2)====================================================================================================
if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow */
pevent->OSEventCnt++; /* Increment semaphore count to register event */
OS_EXIT_CRITICAL();
return (OS_ERR_NONE);
}
OS_EXIT_CRITICAL(); /* Semaphore value has reached its maximum */
return (OS_ERR_SEM_OVF);
(3)===================================================================================================
}

OSSemPost函数实现相对简单,在判断完当前操作是否是sem event之后,就判断当前的event等待group中是否有等待该event的任务,如果有就设置等待该event的任务拥有该信号量的使用权限设置改任务处于RDY状态然后执行任务调度,让等待的任务得以执行,在此有一个巧妙地设计就是对于信号量的计量值OSEventCnt不做操作,因为如果event等待group中有等待任务的话,意味着在此释放信号量,等待任务就获得了信号量。如果在等待group中没有等待任务的话,就会给OSEventCnt做加操作,表示有一个任务释放了该信号量。在此说明的是该函数主要的操作在OS_EventTaskRdy中,其主要功能就是把event的等待group和table中的任务解析出来放到任务Rdy列表中,并把event中的等待任务从列表中删除。

如果信号量的值设置为1的话,就是一个特殊情况,表示只有1个任务拥有信号量,有点互斥的意味,但是与互斥锁不同的是,互斥锁为了防止低优先级占有资源,却因为优先级的低不被执行,而高优先级得不到被低优先级占有的资源而不能执行,使用了优先级继承机制。之后会介绍ucos互斥锁的内核实现。

ucos实时操作系统学习笔记——任务间通信(信号量)的更多相关文章

  1. ucos实时操作系统学习笔记——任务间通信(消息)

    ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...

  2. ucos实时操作系统学习笔记——任务间通信(队列)

    ucos操作系统中的queue机制同样使用了event机制来实现,其实和前面的sem,mutex实现类似,所不同的是对sem而言,任务想获得信号量,对mutex而言,任务想获得的是互斥锁.任务间通信的 ...

  3. ucos实时操作系统学习笔记——任务间通信(互斥锁)

    想讲一下ucos任务间通信中的mutex,感觉其设计挺巧妙,同sem一样使用的是event机制实现的,代码不每一行都分析,因为讲的没邵贝贝老师清楚,主要讲一下mutex的内核是如何实现的.可以理解互斥 ...

  4. ucos实时操作系统学习笔记——操作系统在STM32的移植

    使用ucos实时操作系统是在上学的时候,导师科研项目中.那时候就是网上找到操作系统移植教程以及应用教程依葫芦画瓢,功能实现也就罢了,没有很深入的去研究过这个东西.后来工作了,闲来无聊就研究了一下这个只 ...

  5. ucos实时操作系统学习笔记——内核结构和任务创建

    对于ucos实时操作系统,邵贝贝的那本书已经写得很详细了,我因为之前不深的研究过ucos,所以在这里做一个笔记,写一些个人对该操作系统的理解,仅仅是个人理解,如果有人看到这边随笔有不对的地方,望给我指 ...

  6. RTX51 Tiny实时操作系统学习笔记—初识RTX51 Tiny

     一,RTX51 Tiny简单介绍    RTX51 Tiny是一种实时操作系统(RTOS),能够用它来建立多个任务(函数)同一时候运行的应用(从宏观上看是同一时候运行的,但从微观上看,还是独立运行的 ...

  7. 操作系统学习笔记----进程/线程模型----Coursera课程笔记

    操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进 ...

  8. 操作系统学习笔记5 | 用户级线程 && 内核级线程

    在上一部分中,我们了解到操作系统实现多进程图像需要组织.切换.考虑进程之间的影响,组织就是用PCB的队列实现,用到了一些简单的数据结构知识.而本部分重点就是进程之间的切换. 参考资料: 课程:哈工大操 ...

  9. 深挖计算机基础:趣谈Linux操作系统学习笔记

    参考极客时间专栏<趣谈Linux操作系统>学习笔记 核心原理篇:内存管理 趣谈Linux操作系统学习笔记:第二十讲 趣谈Linux操作系统学习笔记:第二十一讲 趣谈Linux操作系统学习笔 ...

随机推荐

  1. Kali对wifi的破解记录

    好记性不如烂笔头,记录一下. 我是在淘宝买的拓实N87,Kali可以识别,还行. 操作系统:Kali 开始吧. 查看一下网卡的接口.命令如下 airmon-ng 可以看出接口名称是wlan0mon. ...

  2. ABP文档 - 目录

    ABP框架 概览 介绍 多层结构 模块系统 启动配置 多租户 集成OWIN 共同结构 依赖注入 会话 缓存 日志 设置管理 时间 领域层 实体 值对象(新) 仓储 领域服务 工作单元 领域事件(Eve ...

  3. H5坦克大战之【画出坦克】

    今天是个特殊的日子,圣诞节,也是周末,在这里先祝大家圣诞快乐!喜庆的日子,我们可以稍微放松一下,扯一扯昨天雷霆对战凯尔特人的比赛,这场比赛大威少又双叒叕拿下三双,而且是一个45+11+11的超级三双, ...

  4. 编写高质量代码:改善Java程序的151个建议(第8章:异常___建议114~117)

    建议114:不要在构造函数中抛出异常 Java异常的机制有三种: Error类及其子类表示的是错误,它是不需要程序员处理也不能处理的异常,比如VirtualMachineError虚拟机错误,Thre ...

  5. yaf的简单入门

    1.目录结构: 2.入口文件 入口文件是所有请求的入口,一般都借助于rewrite规则,把所有的请求都重定向到这个入口文件. 一个经典的入口文件  public/index.php 3.重写规则 需要 ...

  6. 初识JavaScript

    JavaScript ECMA-262: 变量,函数,对象,数据类型....唯独没有输入和输出. Javascript:包含 ECMA-262,核心 BOM 浏览器对象模型, DOM 文档对象模型 什 ...

  7. 页面布局class常见命名规范

    头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wrapper 左右中:left rig ...

  8. Android之三种网络请求解析数据(最佳案例)

    AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个类,然后调用execute()方法. ...

  9. git提交项目到已存在的远程分支

    今天想提交项目到github的远程分支上,那个远程分支是之前就创建好的,而我的本地关联分支还没创建.   之前从未用github提交到远程分支过,弄了半个钟,看了几篇博文,终于折腾出来.现在把步骤整理 ...

  10. linux下使用shell 自动执行脚本文件

    以下实例本人在Centos6.5 64位操作系统中使用 一.定时复制文件 a.在/usr/local/wfjb_web_back目录下创建 tomcatBack.sh文件 文件内容: #将tomcat ...