UCOSII学习---五、任务通信之信号量

本文深入解析信号量机制,涵盖二值与N值信号量概念,探讨任务如何通过pend操作获取信号量,以及post操作释放信号量的过程。信号量作为进程间通信的重要手段,其有效性直接影响任务对资源的访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:信号量的理解:

信号量的本质是数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号量在此过程中负责数据操作的互斥、同步等功能。

(1)信号量可以分为两种:一种是二值信号量(0和1),一种是N值信号量(计数式信号量)。
二值信号量的意思是可以有多少任务同时享用这个信号量。比如二值信号,就是只有1个任务可以使用。当有一个任务使用该信号量的时候,那么其他需要使用该信号量的任务就必须等待,直到该任务释放该信号量。这种信号量可以看作一把钥匙。
对于N值信号量(计数式信号量),就是说可以同时有N-1个任务同时使用该信号量。对于二值信号量,N=1。

(2)建立信号量的工作必须在任务级代码中或者多任务启动之前完成。

二:任务如何得到信号量的问题:

想得到信号量的任务,必须执行等待操作(pend)。在信号量的建立的时候,我们首先确定了该信号量可以被共享的资源数(N),并将其赋值给pevent->OSEventCnt。如果信号量有效(非0),即pevent->OSEventCnt>0,则信号量减1,任务得以继续运行。如果信号量无效,即pevent->OSEventCnt==0,则等待信号量的任务就被列入等待信号量的任务表中。许多内核允许定义等待超时,当等待时间超过了设定值,该信号量还是无效,则等待该信号量的任务进入就绪态,准备运行,并返回出错代码(等待超时错误)。

三:任务对信号量的释放问题:

任务执行发信号(post)操作来释放信号量。如果没有任务等待信号量,那么信号量的值仅是简单的加1(则信号量大于0,有效);如果有任务等待该信号量,那么就会有另一个任务进入就绪态,信号量的值就不加1。

之后,这个释放的信号量给那个等待中的任务,要看内核如何调度的。收到信号量的任务可能是如下两者之一:

  • 等待任务中,优先级最高的;(uc/os-ii仅支持这种方式)。

  • 最早开始等待信号量的任务(如果是按先进先出FIFO原则)。

四:信号量的有效与无效的问题:

信号量有效:信号量的计算器非0(.OSEventCnt!=0)。信号量有效表示任务对资源可用。

信号量无效:信号量的计算器为0。信号量无效表示任务对目前资源不可用,需要等待其他另一个任务(或者中断服务子程序)发出该信号量(OSSemPost)。

五:关于信号量的三个重要函数:

◆OSSemCreate() 创建一个信号量 (注:由任务或启动代码操作)

创建工作必须在任务级代码中或者多任务启动之前完成。功能是先获取一个事件控制块ECB,写入一些参数。其中调用了OS_EeventWaitListInt()函数,对事件控制块的等待任务列表进行初始化。完成初始化工作后,返回一个该信号量的句柄(Handle)。

该函数初值为0和1的区别:
假设你把信号量的值设为0,有A,B连个任务,当A发出pend请求的时候它发现此事的信号量值为0就把它减1然后挂起等待,等待到什么时候呢?等待任务B执行post操作把信号量的值加1然后唤醒进程A,然后两个进程同步并发执行。。。通俗点解释就是任务A执行到某个地方的时候先停下来睡觉,等待任务B来叫醒它,然后两个任务一起并发运行,也就是几乎同时从那个点开始运行哈。。。
假设信号量的值是1,就是用来互斥的,A,B两个任务只能其中一个任务pend执行成功返回,此时信号量的值是0,另一个在pend请求的时候就必须把自己挂起等待刚刚那个请求成功的任务执行post操作才能唤醒继续执行。

◆OSSemPend() 等待一个信号量 (注:只能由任务操作)

本函数应用于任务试图获得共享资源的使用权、任务需要与其他任务或中断同步及任务需要等待特定事件发生的场合。

如果任务Task_A调用OSSemPend(),且信号量的值有效(非0),那么OSSemPend()递减信号量计数器(.OSEventCnt),并返回该值。换句话说,Task_A获取到共享资源的使用权了,之后就执行该资源。

如果如果任务Task_A调用OSSemPend(),信号量无效(为0),那么OSSemPend()调用OS_EventTaskWait()函数,把Task_A放入等待列表中。(等待到什么时候呢?要看OSSemPost()(或者等待超时情况),由它释放信号量并检查任务执行权,见下资料)

◆OSSemPost() 发出(释放)一个信号量 (注:由任务或中断操作)
本函数其中调用OS_EventTaskRdy()函数,把优先级最高的任务Task_A(在这假如是Task_A,另外假设当前调用OSSemPost()的任务是Task_B)从等待任务列表中去除,并使它进入就绪态。然后调用OSSched()进行任务调度。如果Task_A是当前就绪态中优先级最高的任务,则内核执行Task_A;否则,OSSched()直接返回,Task_B继续执行。

◆OSSemAccept()无等待地请求一个信号量。
一个任务请求一个信号量时,如果该信号量暂时无效,也可以让该任务简单地返回,而不是进入睡眠等待状态。如果有效,则将信号量的计数值减1,然后将信号量的原有计数值返回给调用函数。调用函数需要对该返回值进行检查。如果该值是0,说明该信号量无效。如果该值大于0,说明该信号量有效,同时该值也暗示着该信号量当前可用的资源数。应该注意的是,这些可用资源中,已经被该调用函数自身占用了一个(该计数值已经被减1)。
中断服务子程序要请求信号量时,只能用OSSemAccept()而不能用OSSemPend(),因为中断服务子程序是不允许等待的。

◆OSSemQuery() 查询信号量状态
OSSemQuery()返回就绪列表和信号量的值,在查询之前要先建立一个接收返回值的结构体。因为无需包含Ecb中的类型和消息指针,所以该结构体类型和Ecb是不同的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值