UCOSII使用之信号量,邮箱

摘要:
信号量在ucos II中,为了实现任务之间的同步,使用的同步机制包括信号量、邮箱和消息队列。Cnt是信号量的初始值。如果Semp=OSSemCreate,则此信号表示等待一个或多个事件发生//2、OSSemCreate;//。。。。。OS_ EVENT*功能_缝合;//。。。。。Fun_ Semp=OSSemCreate;//。。。。。(;;)的voidMyTask{//{OSSemPend;//请求信号量PC_DispStr;OSSemPost;//发送信号量OSTimeDlyHMSM;//等待1秒}}voidYouTask{for(;;){OSSemPend;//请求信号量PC_DispStr;OSSemPost;//发送信号量OSTimeDlyHMSM;//等待2秒}。执行MyTask后,OSSemPost//发送信号量。
信号量

在ucos-II中,为了实现任务之间的同步,用到的同步机制有:信号量,邮箱和消息队列。其中这里我主要说下对信号量的使用经验。信号量在创建时,      调用OSSemCreate(INT16U cnt)函数。cnt为信号量的初始值。对cnt赋予不同的值,所起到的作用不同。如果Semp = OSSemCreate(0), 该信号量表示等待一个事件或者多个事件的发生。

      如果我们想对一个公共资源进行互斥访问,例如:如果我们想让两个任务Task1和Task2都可以调用Fun()函数,但不能同时调用,最好定义Semp = OSSemCreate(1),同理在各自的任务中都需要调用OSSemPend(Semp,0,&err)请求此信号量,如果可用,则调用Fun(),然后再调用OSSemPost(Semp)释放该信号量。这里就实现了一个资源的互斥访问。(注:初始化OSSemCreate(1),那么一个任务中有OSSemPend,那么可以执行,执行之后cnt==0,其他任务的OSSemPend无法获得sem,只能等待,除非任务一有OSSemPost,使其cnt++,这样其他任务的Pend可以执行。)同理,如果一个任务要等待n个事件发生后才能执行,则应定义为Semp = OSSemCreate(n)。然后在这n个任务分别运行时调用OSSemPost(Semp),直到这n个事件均发生后,这个任务才能运行。

OSSemCreate(cnt)赋初始值cntOSSemPend一次,cnt-- 一次,OSSemPost一次,cnt++一次。

//1、OSSemCreate (0);
//......
//OS_EVENT *Fun_Semp;
//......

Fun_Semp = OSSemCreate (0);
//......

void  MyTask (void *pdata)
{

.....
    for (;;) 
    {                                           
        OSSemPend(Fun_Semp,0,&err); //请求信号量
   PC_DispStr(0,++y,  s1,  DISP_BGND_BLACK+DISP_FGND_WHITE );
        OSTimeDlyHMSM(0, 0, 1, 0);    //等待1秒
    }
}

......

void  YouTask (void *pdata)
{

......
    for (;;) 
    {           
  PC_DispStr(0,++y,  s2,  DISP_BGND_BLACK+DISP_FGND_WHITE );
  if(YouTaskRun==5)
       OSSemPost(Fun_Semp);  //发送信号量
  YouTaskRun++;            
        OSTimeDlyHMSM(0, 0, 2, 0);    //等待2秒
    }
}

在上例中,MyTask 一直在等待信号量,在信号量没有到来之前无法执行。只有在YouTask 运行了5次,YouTaskRun==5之后,OSSemPost(Fun_Semp);  //发送信号量,MyTask 才得以执行。如果按上例所示,MyTask 只能执行一次,因为YouTask 以后再也不可能使得YouTaskRun==5了。MyTask也就因为无法得到信号量而不能运行。

//2、OSSemCreate (1);
//.....
OS_EVENT *Fun_Semp;
//.....
Fun_Semp = OSSemCreate (1);
//.....
void  MyTask (void *pdata)
{

//..... 
    for (;;) 
    {                                           
        OSSemPend(Fun_Semp,0,&err); //请求信号量
   PC_DispStr(0,++y,  s1,  DISP_BGND_BLACK+DISP_FGND_WHITE );
   OSSemPost(Fun_Semp);  //发送信号量
        OSTimeDlyHMSM(0, 0, 1, 0);    //等待1秒
    }
}

void  YouTask (void *pdata)
{

    for (;;) 
    {                                           
        OSSemPend(Fun_Semp,0,&err); //请求信号量
   PC_DispStr(0,++y,  s2,  DISP_BGND_BLACK+DISP_FGND_WHITE );

   OSSemPost(Fun_Semp);  //发送信号量            
        OSTimeDlyHMSM(0, 0, 2, 0);    //等待2秒
    }
}

在上例中,MyTask、YouTask 都在 等待信号量,由于MyTask优先级高,首先得到信号量开始执行。此时YouTask 还在等待信号量。MyTask 执行完毕,OSSemPost(Fun_Semp);  //发送信号量。YouTask 得到信号量运行后发送信号量,如此反复

 

邮箱

 

/******************************************************************

 Name:            Lambda
 Date:            2013.03.23
 Desciption:        创建两个任务,任务1不断循环发送字符A到字符Z,通过
                 邮箱的方式传递数据给任务2,任务2将从任务1收到的数据
                 通过串口打印在超级终端里。
                                         
*******************************************************************/ 

#include "config.h"

#define     TASK_STK_SIZE    512                        //定义每个堆栈长度为512

OS_STK        TaskStartStk[TASK_STK_SIZE];            //创建起始任务的堆栈
OS_STK        Task1Stk[TASK_STK_SIZE];            //创建功能任务1的堆栈
OS_STK        Task2Stk[TASK_STK_SIZE];            //创建功能任务2的堆栈
OS_EVENT    *TxMbox;                            //定义一个邮箱,用来传递发送消息
OS_EVENT     *AckMbox;                            //定义一个邮箱,用来传递应答消息


void TaskStart(void *pdata);
static void TaskStartCreateTasks(void);
void Task1(void *pdata);
void Task2(void *pdata);


/**********************************************************
                                        Main函数
**********************************************************/
int Main(void)
{
    TargetInit();                 //目标板初始化
    OSInit();                       //uC/OS-II初始化
    OSTimeSet(0);              //设置系统时基,建议予以保留
    OSTaskCreate(TaskStart, (void *)0, &TaskStartStk[TASK_STK_SIZE - 1], 7);    //创建起始任务TaskStart  
    OSStart();

    return 0;
}


/******************************************************************
                         起始任务函数TaskStart
*******************************************************************/ 

void TaskStart(void *pdata)
{

    pdata = pdata;                            //防止编译器报警
    
    TxMbox = OSMboxCreate( (void *)0 );        //创建一个邮箱,用来传递发送消息
    AckMbox = OSMboxCreate( (void *)0 );    //创建一个邮箱,用来传递应答消息
    
    TaskStartCreateTasks();                    //调用该函数来创建更多的功能任务

    while(1){                                //所有的任务都应该是一个无限循环的过程
        OSTimeDlyHMSM(0,0,1,0);            //将该任务挂起1秒,uCOS-II开始调度,让下一个就绪的最高优先级的任务运行
    }

}


/******************************************************************
                 创建功能任务函数TaskStartCreateTasks
*******************************************************************/

static void TaskStartCreateTasks(void)
{
    OSTaskCreate(Task1, (void *)0, &Task1Stk[TASK_STK_SIZE - 1], 8);            //创建功能任务Task1,优先级为8,不传递参数
    OSTaskCreate(Task2, (void *)0, &Task2Stk[TASK_STK_SIZE - 1], 9);            //创建功能任务Task2,优先级为9,不传递参数
}



/******************************************************************
                         功能任务函数Task1
*******************************************************************/

void Task1(void *pdata)
{
    char    TxMsg;
    INT8U err;
    
    pdata = pdata;                                    //防止编译器报警
    
    TxMsg = 'A';    
    while(1)
    {
        OSMboxPost(TxMbox, (void *)&TxMsg);        //把消息A的指针通过邮箱TxMbox发送出去
        OSMboxPend(AckMbox, 0, &err);                //一直等待邮箱AckMbox收到应答信号,只有从任务2收到应答信号后才往下执行
        
        TxMsg++;                                //循环发送字符A到字符Z
        if(TxMsg > 'Z'){
            TxMsg = 'A';
            
        //OSTimeDlyHMSM(0,0,1,0);                    //去掉该函数才能正常打印,但打印速度会非常快; 添加后反而会挂死任务只能打印字符A,就不动了??
                                                //此处的问题还请有经验的朋友指导一下啊。
                                                
        }
    }
}


/******************************************************************
                         功能任务函数Task2
*******************************************************************/

void Task2(void *pdata)
{
    char    *RxMsg;
    INT8U err;

    pdata = pdata;                                        //防止编译器报警
    
    while(1){
        RxMsg = (char *)OSMboxPend(TxMbox,0,&err);        //通过邮箱的方式从任务1处获得数据
        
        Uart_SendString(RxMsg);                            //将获得的数据通过串口打印,Uart_SendString()函数在工程其它文件,此处未给出
        
        OSMboxPost(AckMbox,(void *)1);                    //通过该邮箱发送应答信号给任务1,表明已成功接收到数据
    }
}

 

免责声明:文章转载自《UCOSII使用之信号量,邮箱》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SpringCloud入门之常用的配置文件 application.yml和 bootstrap.yml区别android可拖动排序GridView实现下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【STM32H7】第6章 ThreadX操作系统移植(IAR)

论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514 第6章   ThreadX操作系统移植(IAR) 本章节将为大家介绍ThreadX内核的IAR方式移植和设计框架,理论上不建议初学者直接学习,因为本章节涉及到的知识点很多,建议对ThreadX的应用有一些了解后再...

netty中的UDP

UDP 提供了向多个接收者发送消息的额外传输模式: 多播——传输到一个预定义的主机组; 广播——传输到网络(或者子网)上的所有主机。 本示例应用程序将通过发送能够被同一个网络中的所有主机所接收的消息来演示 UDP 广播的使用。为此,我们将使用特殊的受限广播地址或者零网络地址 255.255.255.255。 发送到这个地址的消息都将会被定向给本地网络...

[ PyQt入门教程 ] PyQt5基本控件使用:消息弹出、用户输入、文件/目录选择对话框

本文主要介绍PyQt界面实现中常用的消息弹出对话框、提供用户输入的输入框、打开文件获取文件/目录路径的文件对话框。学习这三种控件前,先想一下它们使用的主要场景: 1、消息弹出对话框。程序遇到问题需要退出需要弹出错误提示框 、程序执行可能造成的风险需要弹出警告窗口提示用户是否进一步执行等等。 2、用户输入框。比如常见的让用户选择执行的程序分支、yes/no等...

操作系统笔记-1

第一章 操作系统引论 ★计算机操作系统是方便用户、管理和控制计算机软硬件资源的系统软件(或程序集合)。 1.OS的目标:有效性、方便性、可扩充性、开放性 2.OS的作用:1) OS作为用户与计算机硬件系统之间的接口;             ★(用户使用计算机的三种方式:命令、系统调用、图标窗口) 2)OS作为计算机系统资源的管理者;           ...

详解linux进程间通信-消息队列

前言:前面讨论了信号、管道的进程间通信方式,接下来将讨论消息队列。   一、系统V IPC 三种系统V IPC:消息队列、信号量以及共享内存(共享存储器)之间有很多相似之处。 每个内核中的 I P C结构(消息队列、信号量或共享存储段)都用一个非负整数的标识符( i d e n t i f i e r )加以引用。 无论何时创建I P C结构(调用m s...

IDA Pro使用技巧

DA Pro基本简介 IDA加载完程序后,3个立即可见的窗口分别为IDA-View,Named,和消息输出窗口(output Window)。 IDA图形视图会有执行流,Yes箭头默认为绿色,No箭头默认为红色,蓝色表示默认下一个执行块。 在寄存器窗口中显示着每个寄存器当前的值和对应在反汇编窗口中的内存地址。函数在进入时都会保存堆栈地址EBP和E...