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. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  2. 【NLP】Python NLTK处理原始文本

    Python NLTK 处理原始文本 作者:白宁超 2016年11月8日22:45:44 摘要:NLTK是由宾夕法尼亚大学计算机和信息科学使用python语言实现的一种自然语言工具包,其收集的大量公开 ...

  3. ASP.NET Core 中文文档 第四章 MVC(4.5)测试控制器逻辑

    原文: Testing Controller Logic 作者: Steve Smith 翻译: 姚阿勇(Dr.Yao) 校对: 高嵩(Jack) ASP.NET MVC 应用程序的控制器应当小巧并专 ...

  4. 在Visual Studio Code中配置GO开发环境

    一.GO语言安装 详情查看:GO语言下载.安装.配置 二.GoLang插件介绍 对于Visual Studio Code开发工具,有一款优秀的GoLang插件,它的主页为:https://github ...

  5. 分享两种实现Winform程序的多语言支持的解决方案

    因公司业务需要,需要将原有的ERP系统加上支持繁体语言,但不能改变原有的编码方式,即:普通程序员感受不到编码有什么不同.经过我与几个同事的多番沟通,确定了以下两种方案: 方案一:在窗体基类中每次加载并 ...

  6. 【腾讯Bugly干货分享】Android Linker 与 SO 加壳技术

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57e3a3bc42eb88da6d4be143 作者:王赛 1. 前言 Andr ...

  7. HIVE教程

    完整PDF下载:<HIVE简明教程> 前言 Hive是对于数据仓库进行管理和分析的工具.但是不要被“数据仓库”这个词所吓倒,数据仓库是很复杂的东西,但是如果你会SQL,就会发现Hive是那 ...

  8. Hibernate中事务的隔离级别设置

    Hibernate中事务的隔离级别,如下方法分别为1/2/4/8. 在Hibernate配置文件中设置,设置代码如下

  9. spring applicationContext.xml和hibernate.cfg.xml设置

    applicationContext.xml配置 <?xml version="1.0" encoding="UTF-8"?> <beans ...

  10. 免费道路 bzoj 3624

    免费道路(1s 128MB)roads [输入样例] 5 7 21 3 04 5 13 2 05 3 14 3 01 2 14 2 1 [输出样例] 3 2 04 3 05 3 11 2 1 题解: ...