第6章 信号量与互斥信号量管理_第1页
第6章 信号量与互斥信号量管理_第2页
第6章 信号量与互斥信号量管理_第3页
第6章 信号量与互斥信号量管理_第4页
第6章 信号量与互斥信号量管理_第5页
已阅读5页,还剩18页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章信号量与互斥信号量管理

本章主要描述信号量与互斥信号量的概念、功能、原理及其使用方法。

本章主要内容6.1信号量管理

信号量的类型一种是只有0和1两种值的信号量,称为二值信号量;另一种是可以有多种值的信号量,称为计数式信号量,其值的大小取决于信号量的数据类型,如计数式信号量是8位整型变量,则其值可以是0~255,若是16位整型变量,则其值可以是0~65,535。µC/OS-II信号量的两个组成部分一个是信号量的计数值,范围是0~65,535;另一个是由等待该信号量的任务组成的任务等待列表。6.1.1概述6.1.1.1信号量的类型和组成6.1.1.2信号量的功能

信号量可以使用在如下场合:允许一个任务与其它任务或中断同步;取得共享资源的使用权;标志事件的发生。

6.1.1.3对信号量的初始计数值赋值方法 对µC/OS-II信号量初始值的赋值方法如下:信号量的初始值=0~65,535。如果表示一个或者多个事件的发生,那么初始值应设为0。如果是用于对共享资源的访问,那么该初始值应设为1(例如,把它当作二值信号量使用)。如果是用来表示允许任务访问n个相同的资源,那么该初始值应该是n,并把该信号量作为一个可计数的信号量使用。

6.1.1.4信号量管理函数

如表6.1所示,µC/OS-II提供了6种对信号量进行操作的函数,所属文件是OS_SEM.C。

表6.1信号量管理函数一览表函数功能调用者OSSemCreate()建立信号量任务或者启动代码OSSemPend()等待信号量只能是任务OSSemPost()发送信号量任务或者中断OSSemAccept()无等待地请求信号量任务或者中断OSSemDel()删除信号量任务OSSemQuery()查询信号量当前状态任务或者中断6.1.1.5信号量的配置常量

在使用信号量函数之前,必须将OS_CFG.H文件中相应的配置常量设置为0或1,以确定是编译还是裁剪该函数,其配置常量如表6.2所示。表6.2信号量函数配置常量一览表函数配置常量说明系统配置OS_SEM_EN该常量为0时,屏蔽所有信号量函数OSSemCreate()信号量必然包含这3个函数,所以它们没有单独的配置常量。OSSemPend()OSSemPost()OSSemAccept()OS_SEM_ACCEPT_ENOSSemDel()OS_SEM_DEL_ENOSSemQuery()OS_SEM_QUERY_EN6.1.1.6中断、任务与信号量之间的关系

如果信号量用于对共享资源的访问,那么信号量就用钥匙符号。符号旁边的数字N代表可用资源数。对于二值信号量,该值就是1;如果信号量用于表示某事件的发生,那么就用旗帜符号。这时的数字N代表事件已经发生的次数。图6.1任务、中断服务子程序和信号量之间的关系

任务、中断服务子程序与信号量之间的关系如图6.1所示,其中:用钥匙或者旗帜符号来表示信号量。6.1.1.7应用要点

原则上中断和任务可以共享信号量,但并不推荐这样使用,因为信号量一般用于任务级。如果非这样做不可,则中断服务子程序只能用来发送信号量。6.1.2建立一个信号量,OSSemCreate()

6.1.2.1函数原型OS_EVENT*OSSemCreate(INT16Uvalue)功能:OSSemCreate()函数用于建立一个信号量,并对信号量赋予初始计数值。这个初始值就是函数的参数value,可以为0~65,535中的任何值,初始值有自己的设置规则。初始值的设置规则如果信号量用来表示一个或多个事件的发生,那么该信号量的初值通常赋为0;如果信号量用于对共享资源的访问,那么该信号量的初值应赋为1(例如,把它当成二值信号量使用);如果信号量用来表示允许访问n个相同的资源,那么该信号量的初值应赋为n,并把信号量作为一个可计数的信号量使用。返回值:OSSemCreate()函数返回指向分配给所建立的信号量的事件控制块的指针。如果没有可用的事件控制块,OSSemCreate()函数返回空指针。调用者:任务或者启动代码。配置常量:OS_SEM_EN。使用任何信号量函数的前提都是需要用此函数建立信号量。6.1.2建立一个信号量,OSSemCreate()

6.1.2.1函数原型OS_EVENT*OSSemCreate(INT16Uvalue)reentrant功能:OSSemCreate()函数用于建立一个信号量,并对信号量赋予初始计数值。这个初始值就是函数的参数value,可以为0~65,535中的任何值,初始值有自己的设置规则。初始值的设置规则如果信号量用来表示一个或多个事件的发生,那么该信号量的初值通常赋为0;如果信号量用于对共享资源的访问,那么该信号量的初值应赋为1(例如,把它当成二值信号量使用);如果信号量用来表示允许访问n个相同的资源,那么该信号量的初值应赋为n,并把信号量作为一个可计数的信号量使用。调用者:任务或者启动代码。配置常量:OS_SEM_EN。使用任何信号量函数的前提都是需要用此函数建立信号量。函数返回指向分配给所建立的信号量的事件控制块的指针。如果没有可用的事件控制块,OSSemCreate()函数返回空指针。6.1.2.2返回值

图6.3返回之前的ECB数据结构6.1.2.3原理与实现

一、原理二、实现代码图6.2信号量建立计算原理主要流程

6.1.2.4应用范例

程序清单6.2OSSemCreate()应用范例OS_EVENT*AdcSem; //定义一个指向信号量ECB的指针voidmain(void){ OSInit(); .

AdcSem=OSSemCreate(1); //信号量初始值设置为1 . OSStart();}OSSemCreate()函数应用范例如程序清单6.2所示,必须首先定义一个OS_EVENT类型的全局变量,用于保存函数的返回值,以供其它相关函数使用。6.1.3删除一个信号量,OSSemDel()6.1.3.1函数原型OS_EVENT*OSSemDel(OS_EVENT*pevent,INT8Uopt,INT8U*err)reentrant功能:OSSemDel()函数用于删除一个信号量。调用者:只能是任务。配置常量:OS_SEM_EN和OS_SEM_DEL_EN。参数pevent

指向信号量的指针,该指针的值可以在建立信号量时得到;opt

定义信号量删除条件的选项,它有两个选择:OS_DEL_NO_PEND,规定只能在已经没有任何任务等待信号量时,才能删除该信号量;OS_DEL_ALWAYS,规定不管有没有任务在等待,立即删除这个信号量。删除后,所有等待该信号量的任务立即进入就绪状态。err

指向包含错误代码的变量的指针,返回值可能为下列几种之一;OS_NO_ERR

调用成功,信号量被删除;OS_ERR_DEL_ISR

试图在中断服务子程序中删除信号量;OS_ERR_INVALID_OPT

参数opt不是2种合法参数之一;OS_ERR_TASK_WAITING

有任务在等待信号量;OS_ERR_PEVENT_TYPE pevent不是指向信号量的指针;OS_ERR_PEVENT_NULL 没有可用的OS_EVENT数据结构。

6.1.3.2返回值 如果信号量已被删除了,则返回空指针;若信号量没有能被删除,则返回pevent。后一种情况下,应该查看出错代码,以查明原因。6.1.3.3原理 基本原理:所谓删除信号量其实质就是将信号量所属的ECB设置恢复到它在空闲ECB链表中的原始状态,并将这个ECB还给空闲ECB链表。

6.1.3.4应用要点由于其它函数可能还会用到这个信号量,所有在删除信号量之前,必须首先删除等待该信号量的所有任务;当挂起的任务进入就绪状态时,中断是关闭的,这就是说中断延迟与等待信号量的任务的数量密切有关。6.1.4等待一个信号量,OSSemPend()

6.1.4.1函数原型

voidOSSemPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err)reentrant

功能:OSSemPend()函数挂起当前任务直到有其它的任务或中断置位信号量或者信号量超出等待的预期时间。如果在预期的时钟节拍内信号量被置位,μC/OS-Ⅱ默认最高优先级的任务取得信号量并恢复执行。当一个任务需要请求一个信号量时,就需要使用OSSemPend()函数。一个被OSTaskSuspend()函数挂起的任务也可以接受信号量,但这个任务将一直保持挂起状态,直到通过调用OSTaskResume()函数恢复任务的运行。调用者:只能是任务。配置常量:没有单独的配置常量。函数参数:pevent

是指向信号量的指针。该指针的值可以在建立该信号量时得到;timeout

指定的超时时钟节拍数量,如果一个任务在经过了timeout参数指定的时钟节拍后还没有得到需要的信号量时,就恢复运行状态。如果timeout为0,则表示任务将持续的等待信号量。最大的等待时间为65,535个时钟节拍。这个时间长度并不是非常严格的,可能存在一个时钟节拍的误差,因为只有在一个时钟节拍结束后才会减少定义的等待超时时钟节拍。err

是指向包含错误码的变量的指针。OSSemPend()函数返回的错误码可能为下述几种之一:OS_NO_ERR 信号量可用;OS_TIMEOUT 没有在指定的时钟节拍数内得到信号量;OS_ERR_PEND_ISR 从中断调用该函数;OS_ERR_EVENT_TYPE pevent不是指向信号量的指针。当任务调用OSSemPend()函数时,如果信号量的值大于零,OSSemPend()函数递减该值并返回该值;如果调用时信号量等于零,OSSemPend()函数将任务加入该信号量的等待队列,并挂起任务,直到该任务收到信号量。6.1.4.2返回值

OSSemPend()函数没有返回值。6.1.4.3原理与实现基本原理:就是从参数pevent指针所指向的ECB数据结构中,获取成员变量.OSEventCnt的信号量计数器值。若该值大于0,则得到一个信号量;若该值等于0,则挂起任务,等待信号量直到.OSEventCnt=1。程序清单6.5OSSemPend()应用范例OS_EVENT*AdcSem; //定义一个指向信号量ECB的指针voidTask(void*ppdata)reentrant{INT8Uerr;ppdata=ppdata;for(;;){.OSSemPend(AdcSem,0,&err);//无限期等待信号量, //只有得到信号量任务才能执行.}}6.1.4.4应用范例OSSemPend()函数应用范例如程序清单6.5所示,必须在建立信号量前定义一个OS_EVENT类型的全局变量,用于指向信号量ECB。6.1.5发送一个信号量,OSSemPost()

6.1.5.1函数原型INT8UOSSemPost(OS_EVENT*pevent)reentrant功能:OSSemPost()函数用于置位指定的信号量,或者说用于发送信号量。如果指定的信号量是0或大于0,无任务等待信号量,OSSemPost()函数使该信号量加1并返回。如果有任务在等待信号量,最高优先级的任务将得到信号量并进入就绪状态。任务调度函数将进行任务调度,决定当前运行的任务是否仍然为最高优先级的任务。从中断调用,不发生任务切换,这是因为必须等到中断嵌套的最外层的ISR调用OSIntExit()函数后,任务切换才能发生。调用者:可以是任务,也可以是中断配置常量:没有单独的配置常量。函数参数:pevent

指向信号量的指针。该指针的值可以在建立该信号量时得到。6.1.5.2返回值OSSemPost()函数的返回值有如下几种:OS_NO_ERR 信号量成功置位,或者说成功发送;OS_SEM_OVF 信号量的值溢出;OS_ERR_EVENT_TYPE pevent不是指向信号量的指针;OS_ERR_PEVENT_NULL pevent是空指针。6.1.5.3原理与实现基本原理:从参数pevent指针所指向的等待任务列表中查询是否有任务正在等待信号量。若有,则将优先级最高的任务置于就绪,并重新调度任务;若无,则将信号量计数器的值加1。6.1.5.4应用范例

程序清单6.6OSSemPost()应用范例OS_EVENT*AdcSem; //定义一个指向信号量的ECB指针voidTask(void*ppdata)reentrant{INT8Uerr;ppdata=ppdata;for(;;){.err=OSSemPost(AdcSem); //发送信号量.}}6.1.6无等待地请求一个信号量,OSSemAccept()

6.1.6.1函数原型INT16U*OSSemAccept(OS_EVENT*pevent)reentrant功能:OSSemAccept()函数用于查看资源是否可以使用或事件是否发生。与OSSemPend()函数不同,如果事件没有发生,或者资源不可使用,OSSemAccept()函数不挂起任务。调用者:可以是任务,也可以是中断,由于中断服务子程序不能等待,所以该函数常用于中断调用。配置常量:OS_SEM_ACCEPT_EN。函数参数:pevent

指向需要查询的信号量的指针。该指针的值可以在建立信号量时得到。6.1.6.2返回值当调用OSSemAccept()函数时,如果信号量的值大于0,说明共享资源可以使用,这个值被返回调用者,信号量的值减1;如果调用OSSemAccept()函数时,信号量的值等于0,说明共享资源不能使用,返回0。6.1.6.3原理与实现函数的基本原理:通过直接查询参数pevent所指向的ECB中的成员变量.OSEventCnt的值来实现信号量的查询。程序清单6.8OSSemAccept()应用范例OS_EVENT *AdcSem; //定义一个信号量ECB指针voidTask(void*ppdata)reentrant{INT16Uvalue;ppdata=ppdata;for(;;){value=OSSemAccept(AdcSem);//查看共享资源是否可用或事件是否发生 if(value>0){. //运行处理代码}.}}6.1.6.4应用范例OSSemAccept()函数应用范例如程序清单6.8所示。6.1.7查询一个信号量的当前状态,OSSemQuery()

6.1.7.1函数原型INT8UOSSemQuery(OS_EVENT*pevent,OS_SEM_DATA*ppdata)reentrant功能:OSSemQuery()函数用于获取指定信号量的信息。利用OSSemQuery()函数可以获取信号量当前计数值(.OSCnt)、.OSEventTbl[]和.OSEventGrp,不查询.OSEventType和.OSEventPtr。使用之前,应用程序需要先建立类型为OS_SEM_DATA的数据结构,用来保存从信号量的事件控制块中取得的数据。调用者:可以是任务,也可以是中断。配置常量:OS_SEM_QUERY_EN。函数参数:pevent

指向信号量的指针,该指针的值可以在建立信号量时得到;ppdata

指向数据结构OS_SEM_DATA的指针,该数据结构包含下述成员:INT16UOSCnt

当前信号量的计数值;INT8UOSEventTbl[OS_EVENT_TBL_SIZE]

信号量等待队列;INT8UOSEventGrp

等待任务所在的组

6.1.7.2返回值

OSSemQuery()函数的返回值有如下几种:OS_NO_ERR

调用成功;OS_ERR_EVENT_TYPE pevent不是指向信号量的 指针;OS_ERR_PEVENT_NULL pevent是空指针。6.1.7.3原理与实现

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论