信号量

  • 信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务之间同步或者临界资源的互斥访问,常用于协助一组互相竞争的任务来访问临界资源。在多任务系统中,各任务之间需要同步或者互斥实现临界资源的保护,信号量功能可以为功能可以为用户提供这方面的支持
  • 抽象来讲,信号量是一个非负整数所有获取它的任务都会将该整数减一(获取它当然是为了使用资源),当该整数值为零时,所有试图获取它的任务都将处于阻塞状态。通常一个信号量的计数值用于对应有效的资源数,表示剩下的可被占用的互斥资源数。其值的含义分两种情况:
    • 0: 表示没有积累下来的释放信号量操作,且有可能有在此信号量上阻塞的任务
    • 正值,表示有一个或多个释放信号量操作。

二值信号量

  • 二值信号量既可以用于临界资源访问也可以用于同步功能。
  • 二值信号量和互斥信号量(以下使用互斥量表示互斥信号量) 非常相似,但是有一些细
    微差别:互斥量有优先级继承机制, 二值信号量则没有这个机制。这使得二值信号量更偏
    向应用于同步功能(任务与任务间的同步或任务和中断间同步), 而互斥量更偏向应用于
    临界资源的访问。
  • 用作同步时,信号量在创建后应被置为空,任务 1 获取信号量而进入阻塞,任务 2 在
    某种条件发生后,释放信号量,于是任务 1 获得信号量得以进入就绪态,如果任务 1 的优
    先级是最高的,那么就会立即切换任务,从而达到了两个任务间的同步。同样的,在中断
    服务函数中释放信号量, 任务 1 也会得到信号量,从而达到任务与中断间的同步。
    还记得我们经常说的中断要快进快出吗,在裸机开发中我们经常是在中断中做一个标
    记,然后在退出的时候进行轮询处理,这个就是类似我们使用信号量进行同步的,当标记
    发生了,我们再做其他事情。在 FreeRTOS 中我们用信号量用于同步,任务与任务的同步,
    中断与任务的同步,可以大大提高效率。
  • 可以将二值信号量看作只有一个消息的队列, 因此这个队列只能为空或满(因此称为二
    值),我们在运用的时候只需要知道队列中是否有消息即可,而无需关注消息是什么。
  • 多任务系统中,我们经常会使用这个二值信号量,比如,某个任务需要等待一个标
    记,那么任务可以在轮询中查询这个标记有没有被置位, 但是这样子做,就会很消耗 CPU
    资源并且妨碍其它任务执行, 更好的做法是任务的大部分时间处于阻塞状态(允许其它任
    务执行),直到某些事件发生该任务才被唤醒去执行。可以使用二进制信号量实现这种同
    步, 当任务取信号量时,因为此时尚未发生特定事件,信号量为空,任务会进入阻塞状态;
    当事件的条件满足后,任务/中断便会释放信号量, 告知任务这个事件发生了, 任务取得信
    号量便被唤醒去执行对应的操作,任务执行完毕并不需要归还信号量, 这样子的 CPU 的效
    率可以大大提高, 而且实时响应也是最快的。
    再比如某个任务使用信号量在等中断的标记的发生,在这之前任务已经进入了阻塞态,
    在等待着中断的发生,当在中断发生之后,释放一个信号量,也就是我们常说的标记,当
    它退出中断之后,操作系统会进行任务的调度,如果这个任务能够运行,系统就会把等待
    这个任务运行起来,这样子就大大提高了我们的效率。

计数信号量

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

二值信号量与消息队列

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; (1)
UBaseType_t uxLength; (2)
UBaseType_t uxItemSize; (3)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;

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

  • 如果信号量是二值信号量、互斥信号量,这个值是 1 则表示有可用信号量,如果
    是 0 则表示没有可用信号量。
  • 如果是计数信号量,这个值表示可用的信号量个数,在创建计数信号量的时候会
    被初始化一个可用信号量个数 uxInitialCount,最大不允许超过创建信号量的初始
    值 uxMaxCount。

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

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

(3):如果控制块结构体是用于消息队列: uxItemSize 表示单个消息的大小; 如果控制块结构体被用于信号量的时候,则无需存储空间,为 0 即可。
(4):信号量和消息队列共用一个结构体, uxMessageWaiting表示信号量的值默认是0,
uxLength 表示信号量最大可用的值
(5):在获取信号量之前要先释放,然后再获取

互斥信号量

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

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

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

  • 优先级翻转:举个例子,现在有 3 个任务分别为 H 任务(High)、 M 任务(Middle)、 L 任务
    (Low), 3 个任务的优先级顺序为 H 任务>M 任务>L 任务。正常运行的时候 H 任务可以
    打断 M 任务与 L 任务, M 任务可以打断 L 任务,假设系统中有一个资源被保护了,此时该
    资源被 L 任务正在使用中,某一刻, H 任务需要使用该资源,但是 L 任务还没使用完, H
    任务则因为申请不到资源而进入阻塞态, L 任务继续使用该资源,此时已经出现了“优先
    级翻转”现象,高优先级任务在等着低优先级的任务执行,如果在 L 任务执行的时候刚好
    M 任务被唤醒了,由于 M 任务优先级比 L 任务优先级高,那么会打断 L 任务,抢占了
    CPU 的使用权,直到 M 任务执行完,再把 CUP 使用权归还给 L 任务, L 任务继续执行,
    等到执行完毕之后释放该资源, H 任务此时才从阻塞态解除,使用该资源。这个过程,本
    来是最高优先级的 H 任务,在等待了更低优先级的 L 任务与 M 任务,其阻塞的时间是 M
    任务运行时间+L 任务运行时间,这只是只有 3 个任务的系统,假如很多个这样子的任务打
    断最低优先级的任务,那这个系统最高优先级任务岂不是崩溃了,这个现象是绝对不允许
    出现的,高优先级的任务必须能及时响应。所以,没有优先级继承的情况下,使用资源保
    护,其危害极大

  • 互斥信号量不能再中断服务函数中使用,因为其特有的优先级继承机制只在任务中起作用,在终端的上下文环境中不起作用。

递归信号量

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

FreeRTOS中多种信号量相关推荐

  1. 正点原子FreeRTOS(中)

    更多干货推荐可以去牛客网看看,他们现在的IT题库内容很丰富,属于国内做的很好的了,而且是课程+刷题+面经+求职+讨论区分享,一站式求职学习网站,最最最重要的里面的资源全部免费!!!点击进入------ ...

  2. linux模块移植到freertos,FATFS在嵌入式操作系统FreeRTOS中的移植与应用

    摘 要: FreeRTOS作为一款免费的实时操作系统,系统内核小.裁剪方便.移植性好,广泛应用于对成本敏感的小型嵌入式系统中,但是FreeRTOS本身不带文件管理功能,不便于很多需要经常进行文件存储与 ...

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

    从零入门 FreeRTOS操作系统之信号量 1 信号量的基本概念 信号量 (Semaphore) 是一种实现任务间通信的机制,可以实现任务之间同步或临界资源的互斥访问,常用于协助一组相互竞争的任务来访 ...

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

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

  5. 嵌入式 freertos_应嵌入式开发人员的要求:在Amazon FreeRTOS中检测错误

    嵌入式 freertos 简要介绍项目 (Briefly about projects) To begin with, I'll tell you a bit about the forerunner ...

  6. FreeRTOS中mutex用法

    FreeRTOS中mutex用法: FreeRTOS为了解决资源保护的问题引入了互斥量(Mutex). Mutex 的发音是 /mjuteks/ ,其含义为互斥(体),这个词是Mutual Exclu ...

  7. Linux 信号量 源码,一文读懂go中semaphore(信号量)源码

    运行时信号量机制 semaphore 前言 最近在看源码,发现好多地方用到了这个semaphore. 本文是在go version go1.13.15 darwin/amd64上进行的 作用是什么 下 ...

  8. 微信支付id出现的重复支付解决方法和app应用中多种支付方式之间的对比

    微信支付id出现的重复支付解决方法和app应用中多种支付方式之间的对比 参考文章: (1)微信支付id出现的重复支付解决方法和app应用中多种支付方式之间的对比 (2)https://www.cnbl ...

  9. 并发教程--JAVA5中 计数信号量(Counting Semaphore)例子

    并发教程--JAVA5中 计数信号量(COUNTING SEMAPHORE)例子 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java中的计数信息量(C ...

最新文章

  1. 使用Junit4时问题
  2. Python datetime astimezone()方法与示例
  3. 支付宝国庆消费报告出炉:景区消费涨9倍
  4. android cardview控件,CardView控件的使用方式
  5. C#泛型委托Predicate、Action、Func
  6. java给mongo数组添加_如何使用具有新值的java在mongodb中的现有集合中追加现有数组...
  7. fatal error: gnu/stubs-n64_hard_2008.h: No such file or directory
  8. 微信小游戏(打飞机1)
  9. python如何使用sdk_如何通过Python访问Kvaser CANlib 软件开发包|Kvaser CANlib SDK的应用...
  10. 基于selenium的python模拟登陆虎牙发送弹幕并截取主播头像
  11. r语言平均值显著性检验_R语言与显著性检验学习笔记
  12. 总结1_1:常用周期函数
  13. 实习日记——Day16
  14. 大学语文 · 期末复习知识点汇总
  15. C语言——求n天后的日期
  16. 6.1 CUDA: pinned memory固定存储
  17. 不会吧,不会吧,全网最细汉诺塔讲解,不会有人不知道吧。面试官直呼内行,看完只想默默找水喝(C语言)
  18. 飞凌Linux版LS1028A嵌入式开发板测评分享
  19. noip 2018游记
  20. 帝国php调用文章列表,帝国CMS模板中:使用php调用最新文章的代码(非灵动和万能标签)...

热门文章

  1. 计算机制图笔记本需要什么配置,绘图笔记本需要什么配置?
  2. EXCEL的VLOOKUP匹配失败是什么原因呢
  3. JQuery UI的拖拽功能
  4. 扔垃圾前得先“刷脸”?北京这个小区垃圾分类真的用上了“人脸识别”!
  5. iphone8 android传文件,如何从iPhone或Android将数据传输到新的iPhone 8
  6. zealer情感机器人_你曾经想象的到来——中文版temi机器人
  7. 史上最污的技术解读,我竟然秒懂了(上)
  8. HTML的基本结构标签(html,head,title,body)
  9. 软考新思维--2017年上半年信息系统项目管理师上午试题分析与答案(试题1-5题)
  10. 软件设计师必考精华 - 下午答题