从零入门 FreeRTOS操作系统之信号量

1 信号量的基本概念

信号量 (Semaphore) 是一种实现任务间通信的机制,可以实现任务之间同步或临界资源的互斥访问,常用于协助一组相互竞争的任务来访问临界资源。

在多任务系统中,各任务之间需要同步或互斥实现临界资源的保护,信号量功能可以为用户提供这方面的支持。

抽象的来讲,信号量是一个非负整数,所有获取它的任务都会将该整数减 1,当该整数值为零时,所有试图获取它的任务都将处于阻塞状态。

通常一个信号量的计数值用于对应有效的资源数,表示剩下的可被占用的互斥资源数。其值的含义分两种情况:

  • 0:表示没有积累下来的释放信号量操作,且有可能有在此信号量上阻塞的任务。
  • 正值:表示有一个或多个释放信号量操作。

2 二值信号量

二值信号量既可以用于临界资源访问也可以用于同步功能。

二值信号量和互斥信号量(以下使用互斥量表示互斥信号量)非常相似,但是有一些细微差别:互斥量有优先级继承机制,二值信号量则没有这个机制。这使得二值信号量更偏向应用于同步功能(任务与任务间的同步或任务和中断间同步),而互斥量更偏向应用于临界资源的访问。

用作同步时,信号量在创建后应被置为空,任务 1 获取信号量而进入阻塞,任务 2 在某种条件发生后,释放信号量,于是任务 1 获得信号量得以进入就绪态,如果任务 1 的优先级是最高的,那么就会立即切换任务,从而达到了两个任务间的同步。同样的,在中断服务函数中释放信号量,任务 1 也会得到信号量,从而达到任务与中断间的同步。

我们知道中断要快进快出,因此在裸机开发中我们经常是在中断中做一个标
记,然后在退出的时候进行轮询处理,这个就是类似我们使用信号量进行同步的,当标记发生了,我们再做其他事情。在 FreeRTOS 中我们用信号量用于同步,任务与任务的同步、中断与任务的同步,可以大大提高效率。

可以将二值信号量看作只有一个消息的队列,因此这个队列只能为空或满(因此称为二值),我们在运用的时候只需要知道队列中是否有消息即可,而无需关注消息是什么。

3 计数信号量

二进制信号量可以被认为是长度为 1 的队列,而计数信号量则可以被认为长度大于 1 的队列,信号量使用者依然不必关心存储在队列中的消息,只需关心队列是否有消息即可。

顾名思义,计数信号量肯定是用于计数的,在实际的使用中,我们常将计数信号量用于事件计数与资源管理。每当某个事件发生时,任务或者中断将释放一个信号量(信号量计数值加 1),当处理事件时(一般在任务中处理),处理任务时取走该信号量(信号量计数值减 1),信号量的计数值则表示还有多少个事件没被处理。此外,系统还有很多资源,我们也可以使用计数信号量进行资源管理,信号量的计数值表示系统中可用的资源数目,任务必须先获取到信号量才能获取资源访问权,当信号量的计数值为零时表示系统没有可用的资源,但是要注意,在使用完资源的时候必须归还信号量,否则当计数值为 0 的时候任务就无法访问该资源了。

计数型信号量允许多个任务对其进行操作,但限制了任务的数量。比如有一个停车场,里面只有 100 个车位,那么能停的车只有 100 辆,也相当于我们的信号量有 100 个,假如一开始停车场的车位还有 100 个,那么每进去一辆车就要消耗一个停车位,车位的数量就要减一,对应的,我们的信号量在使用之后也需要减一,当停车场停满了100 辆车的时候,此时的停车位为 0,再来的车就不能停进去了,否则将造成事故,也相当于我们的信号量为 0,后面的任务对这个停车场资源的访问也无法进行,当有车从停车场离开的时候,车位又空余出来了,那么,后面的车就能停进去了,我们信号量的操作也是一样的,当我们释放了这个资源,后面的任务才能对这个资源进行访问。

4 互斥信号量

互斥信号量其实是特殊的二值信号量,由于其特有的优先级继承机制从而使它更适用于简单互锁,也就是保护临界资源。

用作互斥时,信号量创建后可用信号量个数应该是满的,任务在需要使用临界资源时,(临界资源是指任何时刻只能被一个任务访问的资源),先获取互斥信号量,使其变空,这样其他任务需要使用临界资源时就会因为无法获取信号量而进入阻塞,从而保证了临界资源的安全。

在操作系统中,我们使用信号量的很多时候是为了给临界资源建立一个标志,信号量表示了该临界资源被占用情况。这样,当一个任务在访问临界资源的时候,就会先对这个资源信息进行查询,从而在了解资源被占用的情况之后,再做处理,从而使得临界资源得到有效的保护。

5 递归信号量

递归信号量,见文知义,递归嘛,就是可以重复获取调用的,本来按照信号量的特性,每获取一次可用信号量个数就会减少一个,但是递归则不然,对于已经获取递归互斥量的任务可以重复获取该递归互斥量,该任务拥有递归信号量的所有权。任务成功获取几次递归互斥量,就要返还几次,在此之前递归互斥量都处于无效状态,其他任务无法获取,只有持有递归信号量的任务才能获取与释放。

6 二值信号量运作机制

创建信号量时,系统会为创建的信号量对象分配内存,并把可用信号量初始化为用户自定义的个数, 二值信号量的最大可用信号量个数为 1

任何任务都可以从创建的二值信号量资源中获取一个二值信号量,获取成功则返回正确,否则任务会根据用户指定的阻塞超时时间来等待其它任务/中断释放信号量。在等待这段时间,系统将任务变成阻塞态,任务将被挂到该信号量的阻塞等待列表中。

在二值信号量无效的时候,假如此时有任务获取该信号量的话,那么任务将进入阻塞状态。

假如某个时间中断/任务释放了信号量,其过程如下图所示。

由于获取无效信号量而进入阻塞态的任务将获得信号量并且恢复为就绪态,二值信号量运作机制如下图所示。

7 计数信号量运作机制

计数信号量可以用于资源管理,允许多个任务获取信号量访问共享资源,但会限制任务的最大数目。访问的任务数达到可支持的最大数目时,会阻塞其他试图获取该信号量的任务,直到有任务释放了信号量。这就是计数型信号量的运作机制,虽然计数信号量允许多个任务访问同一个资源,但是也有限定,比如某个资源限定只能有3 个任务访问,那么第4 个任务访问的时候,会因为获取不到信号量而进入阻塞,等到有任务(比如任务1)释放掉该资源的时候,第4 个任务才能获取到信号量从而进行资源的访问,其运作的机制如下图所示。

8 信号量控制块

信号量 API 函数实际上都是宏,它使用现有的队列机制,这些宏定义在 semphr.h 文件中,如果使用信号量或者互斥量,需要包含 semphr.h 头文件。所以 FreeRTOS 的信号量控制块结构体与消息队列结构体是一模一样的,只不过结构体中某些成员变量代表的含义不一样而已。

typedef struct QueueDefinition
{int8_t *pcHead;int8_t *pcTail;int8_t *pcWriteTo;union{int8_t *pcReadFrom;UBaseType_t uxRecursiveCallCount;} u;List_t xTasksWaitingToSend;List_t xTasksWaitingToReceive;volatile UBaseType_t uxMessagesWaiting;UBaseType_t uxLength;UBaseType_t uxItemSize;volatile int8_t cRxLock;volatile int8_t cTxLock;#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )uint8_t ucStaticallyAllocated;#endif#if ( configUSE_QUEUE_SETS == 1 )struct QueueDefinition *pxQueueSetContainer;#endif#if ( configUSE_TRACE_FACILITY == 1 )UBaseType_t uxQueueNumber;uint8_t ucQueueType;#endif} xQUEUE;typedef xQUEUE Queue_t;

volatile UBaseType_t uxMessagesWaiting;:如果控制块结构体是用于消息队列: uxMessagesWaiting 用来记录当前消息队列的消息个数;如果控制块结构体被用于信号量的时候,这个值就表示有效信号量个数,有以下两种情况:

  • 如果信号量是二值信号量、互斥信号量,这个值是 1 则表示有可用信号量,如果是 0 则表示没有可用信号量。

  • 如果是计数信号量,这个值表示可用的信号量个数,在创建计数信号量的时候会被初始化一个可用信号量个数 uxInitialCount,最大不允许超过创建信号量的初始值 uxMaxCount

UBaseType_t uxLength;:如果控制块结构体是用于消息队列:uxLength 表示队列的长度,也就是能存放多少消息;如果控制块结构体被用于信号量的时候,·uxLength· 表示最大的信号量可用个数,会有以下两种情况:

  • 如果信号量是二值信号量、互斥信号量,uxLength 最大为 1,因为信号量要么是有效的,要么是无效的。
  • 如果是计数信号量,这个值表示最大的信号量个数,在创建计数信号量的时候将由用户指定这个值 uxMaxCount

UBaseType_t uxItemSize;:如果控制块结构体是用于消息队列:uxItemSize 表示单个消息的大小;如果控制块结构体被用于信号量的时候,则无需存储空间,为 0 即可。

从零入门 FreeRTOS操作系统之信号量相关推荐

  1. 从零入门 FreeRTOS 操作系统之任务调度器

    从零入门 FreeRTOS 操作系统之任务调度器 1 任务调度器的概念 FreeRTOS 中提供的任务调度器是基于优先级的全抢占式调度:在系统中除了中断处理函数.调度器上锁部分的代码和禁止中断的代码是 ...

  2. 从零入门 FreeRTOS 操作系统之任务的概念

    从零入门 FreeRTOS 操作系统之任务的概念 从系统的角度看,任务是竞争系统资源的最小运行单元.FreeRTOS 是一个支持多任务的操作系统.在 FreeRTOS 中,任务可以使用或等待 CPU. ...

  3. 从零入门 FreeRTOS 操作系统之创建任务流程

    从零入门 FreeRTOS 操作系统之创建任务 1 启动方式 在 main() 函数中将硬件和 RTOS 系统先初始化好,在主函数内部创建一个启动任务后就启动调度器,然后在启动任务里面创建各种应用任务 ...

  4. xsemaphoretake返回_【FreeRTOS操作系统教程】第21章 FreeRTOS计数信号量

    第21章 FreeRTOS计数信号量 本章节开始讲解FreeRTOS任务间的同步和资源共享机制,计数信号量.FreeRTOS中计数信号量的源码实现是基于消息队列实现的. 本章教程配套的例子含Corte ...

  5. FreeRTOS 任务计数信号量,任务二值信号量,任务事件标志组,任务消息邮箱

    以下基础内容转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 计数信号量的另一种实现方式----基于任务通知(Task Not ...

  6. Arduino UNO跑FreeRTOS操作系统

    实验室翻到一个小开发板--Arduino UNO,学了两天,有点意思哈!比stm32简洁,直接.使用前没那么多配置,也是跑c/c++的,这么简单,以后用到再玩玩吧 参考资料: Arduino运行Fre ...

  7. 零入门kubernetes网络实战-31->基于bridge+veth pair+MASQUERADE技术实现内网可以访问外网

    <零入门kubernetes网络实战>视频专栏地址 https://www.ixigua.com/7193641905282875942 本篇文章视频地址(稍后上传) 本篇文章我们使用na ...

  8. FreeRTOS操作系统——任务通知模拟消息邮箱及事件标志组(十八)

    FreeRTOS操作系统学习 文章目录 FreeRTOS操作系统学习 一.消息邮箱API函数 二.消息邮箱实验 三.事件标志组实验 总结 一.消息邮箱API函数 任务通知也可用来向任务发送数据,但是相 ...

  9. 从零入门机器学习之Linux系统详解

      大家好,我是herosunly.985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用.曾获得阿里云天池比赛第一名,科大讯飞比赛第三名,CCF比赛第四名.拥有多项发明专利.对机器学 ...

最新文章

  1. CSS深入理解之margin
  2. python编程自学能学会吗-python编程还能自学?怎么能学好? - 【大连东软睿道】
  3. boost::mp11::mp_unique_if相关用法的测试程序
  4. pro调用python libs_使用WingPro 7 设置Python路径的方法
  5. plsql数据库异常---plsql 登录后,提示数据库字符集(AL32UTF8)和客户端字符集(ZHS16GBK)不一致 .
  6. 数据结构相关代码-简介
  7. python机器学习库sklearn——逻辑回归
  8. __imp__ZN11QSerialPortC1EP7QObject
  9. 解决”企业证书打包的ipa,点击app提示未受信任的企业级开发者“的问题
  10. 计算机的基本知识理论,计算机基本理论基础知识总汇
  11. Deep Crossing: Web-Scale Modeling without Manually Crafted Combinatorial Features(2016)
  12. 教你学Python16-消息安全加解密/数字签名
  13. Sobel,拉普拉斯算子
  14. Windows server 2019从头搭建私网***
  15. SQL语句-各种查询
  16. 盘点PDF文件转Word文档的四种高效率转换方法
  17. 【C++实现】编译原理 免考小队 FIRSTVT集生成算法
  18. 如何提升企业形象?写字楼门禁是第一关
  19. windows 可以禁用的服务盘点
  20. L1-040 最佳情侣身高差(10 分)

热门文章

  1. Qt 并行计算圆周率示例
  2. 骑士 java_在递归骑士之旅中正确声明变量(Java作业)
  3. 文本分类入门(六)训练Part 3
  4. 科技论文的几种类型-如何写好科技论文之我见(二)
  5. 滴滴笔试编程题第一题
  6. 零件分组pascal程序
  7. python包含某个数字_python编程练习---有序数组中,快速查找是否包含指定数字,并返回其下标...
  8. 解决浏览器刷新vuex数据丢失问题
  9. # HDU - 6185 Covering
  10. keras 的使用例子