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 > 0) {                      /* See if called from ISR ...                         */
        return ((OS_EVENT *)0);                  /* ... can‘t CREATE from an ISR                       */
    }
    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                    /* Get next free event control block                  */
    if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) {
        pevent->OSEventType    = OS_EVENT_TYPE_MBOX;
        pevent->OSEventCnt     = 0;
        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 *)0);
    }
    if (OSIntNesting > 0) {                           /* See if called from ISR ...                    */
        *perr = OS_ERR_PEND_ISR;                      /* ... can‘t PEND from an ISR                    */
        return ((void *)0);
    }
    if (OSLockNesting > 0) {                          /* See if called with scheduler locked ...       */
        *perr = OS_ERR_PEND_LOCKED;                   /* ... can‘t PEND when locked                    */
        return ((void *)0);
    }
    OS_ENTER_CRITICAL();
    pmsg = pevent->OSEventPtr;
    if (pmsg != (void *)0) {                          /* See if there is already a message             */
        pevent->OSEventPtr = (void *)0;               /* 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 *)0;
            *perr =  OS_ERR_PEND_ABORT;               /* Indicate that we aborted                      */
             break;

        case OS_STAT_PEND_TO:
        default:
             OS_EventTaskRemove(OSTCBCur, pevent);
             pmsg = (void *)0;
            *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  *)0;    /* Clear event pointers                          */
    OSTCBCur->OSTCBMsg           = (void      *)0;    /* 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 != 0) {                    /* 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 *)0) {            /* 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的使用,因为如果有多个任务同时使用的话,就会存在是否是当前任务想要的信息,如果不是的话有可能把别的任务的消息给去处并释放掉了,所以使用时需要注意。

时间: 2024-10-03 13:27:52

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

ucos实时操作系统学习笔记——任务间通信(信号量)

ucos实时操作系统的任务间通信有好多种,本人主要学习了sem, mutex, queue, messagebox这四种.系统内核代码中,这几种任务间通信机制的实现机制相似,接下来记录一下本人对核心代码的学习心得,供以后回来看看,不过比较遗憾的是没有仔细学习扩展代码的功能实现部分.ucos操作系统的内核代码实现相对简单,但是对理解其他操作系统内核相同功能有帮助. ucos的任务间通信机制主要是基于event实现的,其实理解这个event不用翻译成中文事件,就叫event感觉还更容易接收.下面是操

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

想讲一下ucos任务间通信中的mutex,感觉其设计挺巧妙,同sem一样使用的是event机制实现的,代码不每一行都分析,因为讲的没邵贝贝老师清楚,主要讲一下mutex的内核是如何实现的.可以理解互斥锁是设置信号量值为1时候的特殊情况,与之不同的地方是互斥锁为了避免优先级反转采用了优先级继承机制,本文主要讲一下互斥锁的创建,pend和post,对应的函数是OSMutexCreate,OSMutexPend,OSMutexPost,当然讲函数也不会所有的扩展功能都讲,只是讲一下主干部分,下面贴出来

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

使用ucos实时操作系统是在上学的时候,导师科研项目中.那时候就是网上找到操作系统移植教程以及应用教程依葫芦画瓢,功能实现也就罢了,没有很深入的去研究过这个东西.后来工作了,闲来无聊就研究了一下这个只有几千行代码的操作系统,也没所有的代码都看,只是看了其中部分内容.自己还自不量力的尝试着去写过简单的操作系统,最后写着写着就被带到了ucos的设计思路上了,后来干脆就“copy”代码了,虽说对操作系统内核的理解有很大的帮助,但是很是惭愧啊,智力不够,对操作系统内核的设计者更加仰慕,O(∩_∩)O哈哈

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

 一,RTX51 Tiny简单介绍 RTX51 Tiny是一种实时操作系统(RTOS),能够用它来建立多个任务(函数)同一时候运行的应用(从宏观上看是同一时候运行的,但从微观上看,还是独立运行的).嵌入式应用系统常常有这样的需求.RTOS能够提供调度.维护.同步等功能. 实时操作系统能灵活的调度系统资源,像CPU和存储器,而且提供任务间的通信.RTX51 Tiny是一个功能强大的RTOS,且易于使用,它用于8051系列的微控制器.该RTOS最多支持16个任务,基于RTX51 Tiny构建的应用程

计算机操作系统学习笔记_1_操作系统概述

操作系统概述 一.操作系统的概念.特征.功能和提供的服务 1.操作系统的概念     操作系统是计算机系统中最重要.最基本的系统软件,操作系统位于硬件和用户程序之间.    对于用户来讲:它能向用户提供使用计算机的接口;    从资源管理角度来看:它能管理计算机软硬件资源,提高其利用率;    再者,利用虚拟机技术(如WMWare,VirtualBox,Java虚拟机等),扩展了计算机的功能和使用范围.     因此,操作系统的定义为:操作系统是控制和管理计算机软.硬件资源,以尽可能合理.高效的

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

操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进程创建.撤销.阻塞.唤醒.... 0.2 线程模型 为什么引入线程 线程的组成 线程机制的实现 用户级线程.核心级线程.混合方式 1. 进程的基本概念 1.1 多道程序设计 允许多个程序同时进入内存运行,目的是为了提高CPU系统效率 1.2 并发环境与并发程序 并发环境: 一段时间间隔内,单处理器上

Linux 操作系统学习笔记

一,unix 1.unix 特点 伸缩性强,开放性好, 2.基本原则 所有对象,硬件都是文件 配置数据以文本形式保存 短小的单目的程序构成 多个程序合作完成复杂任务 3.gnu 基本原则是共享,建立自由开放的unix系统 1984年 richard stallman 发起 基本体系是micro kernel 4.gpl Copyleft 原作者所有权 5.linux起源 Linustorvalds, 自由的类unix操作系统, 遵循gnu和gpl 6.linux 可以实现unix功能 遵循开源许

计算机操作系统学习笔记_4_进程管理 --处理机调度

h3.western { font-family: "Liberation Sans",sans-serif; }h3.cjk { font-family: "微软雅黑"; }h3.ctl { font-family: "AR PL UMing CN"; }h1 { margin-bottom: 0.21cm; }h1.western { font-family: "Liberation Sans",sans-serif; f

计算机操作系统学习笔记_2_进程管理 --进程与线程(上)

h3.western { font-family: "Liberation Sans",sans-serif; }h3.cjk { font-family: "微软雅黑"; }h3.ctl { font-family: "AR PL UMing CN"; }h2.western { font-family: "Liberation Sans",sans-serif; font-size: 16pt; }h2.cjk { fon