FreeRTOS系列第19篇---FreeRTOS信号量

来自:http://blog.csdn.net/zhzht19861011/article/details/50835613


本文介绍信号量的基础知识,详细源码分析见《FreeRTOS高级篇6---FreeRTOS信号量分析》

1.信号量简介

      FreeRTOS的信号量包括二进制信号量计数信号量互斥信号量(以后简称互斥量)和递归互斥信号量(以后简称递归互斥量)。

      我们可以把互斥量和递归互斥量看成特殊的信号量。互斥量和信号量在用法上不同:

  • 信号量用于同步,任务间或者任务和中断间同步;
  • 互斥量用于互锁,用于保护同时只能有一个任务访问的资源,为资源上一把锁。
  • 信号量用于同步时,一般是一个任务(或中断)给出信号,另一个任务获取信号;互斥量必须在同一个任务中获取信号、同一个任务给出信号。
  • 互斥量具有优先级继承,信号量没有。
  • 互斥量不能用在中断服务程序中,信号量可以。
  • 创建互斥量和创建信号量的API函数不同,但是共用获取和给出信号API函数;

2.二进制信号量

      二进制信号量既可以用于互斥功能也可以用于同步功能。

      二进制信号量和互斥量非常相似,但是有一些细微差别:互斥量包含一个优先级继承机制,二进制信号量则没有这个机制。这使得二进制信号量更好的用于实现同步(任务间或任务和中断间),互斥量更好的用于实现简单互斥。本节仅描述用于同步的二进制信号量。

      信号量API函数允许指定一个阻塞时间。当任务企图获取一个无效信号量时,任务进入阻塞状态,阻塞时间用来确定任务进入阻塞的最大时间,阻塞时间单位为系统节拍周期时间。如果有多个任务阻塞在同一个信号量上,那么当信号量有效时,具有最高优先级别的任务最先解除阻塞。

      可以将二进制信号量看作只有一个项目(item)的队列,因此这个队列只能为空或满(因此称为二进制)。任务和中断使用队列无需关注谁控制队列---只需要知道队列是空还是满。利用这个机制可以在任务和中断之间同步。

      考虑这样一种情况,一个任务用来维护外设。使用轮询的方法会浪费CPU资源并且妨碍其它任务执行。更好的做法是任务的大部分时间处于阻塞状态(允许其它任务执行),直到某些事件发生该任务才执行。可以使用二进制信号量实现这种应用:当任务取信号量时,因为此时尚未发生特定事件,信号量为空,任务会进入阻塞状态;当外设需要维护时,触发一个中断服务例程,该中断服务仅仅给出信号量(向队列写数据)。任务只是取信号,并不需要归还,中断服务只是给信号。

      任务的优先级可以用于确保外设及时获得维护。还可以使用队列来代替二进制信号量。中断例程可以捕获与外设事件相关的数据并将它发往任务的队列。任务发现队列数据有效时解除阻塞,如果需要,则进行数据处理。第二种方案使得中断执行尽可能的短,其它处理过程可以在任务中实现。

      注:断程序中决不可使用无“FromISR”结尾的API函数。

      注:在大部分应用场合,任务通知都可以代替二进制信号量,并且速度更快、生成的代码更少。


图1-1:中断和任务之间同步---使用信号量

      如图1-1所示,程序开始运行时,信号量无效,因此任务阻塞在这个信号量下。一段时间后,一个中断发生,在中断服务程序中使用API函数xSemaphoreGiveFromISR()给出了一个信号,信号量变得有效。当退出中断服务程序后,执行上下文切换,任务解除阻塞,使用API函数xSemaphoreTake()取走信号量并执行任务。之后信号量变得无效,任务再次进入阻塞。

3.计数信号量

      二进制信号量可以被认为是长度为1的队列,计数信号量则可以被认为长度大于1的队列。此外,信号量使用者不必关心存储在队列中的数据,只需关心队列是否为空。

      通常计数信号量用于下面两种事件:

  1. 计数事件:在这种场合下,每当事件发生,事件处理程序将给出一个信号(信号量计数值增1),当处理事件时,处理程序会取走信号量(信号量计数值减1)。因此,计数值是事件发生的数量和事件处理的数量差值。在这种情况下,计数信号量在创建时其值为0。
  2. 资源管理:这种用法下,计数值表示有效的资源数目。任务必须先获取信号量才能获取资源控制权。当计数值减为零时表示没有的资源。当任务完成后,它会返还信号量---信号量计数值增加。在这种情况下,信号量创建时,计数值等于最大资源数目。

      注:中断程序中决不可使用无“FromISR”结尾的API函数。

      注:在大部分应用场合,任务通知都可以代替计数信号量,并且速度更快、生成的代码更少。

4.互斥量

      互斥量是一个包含优先级继承机制的二进制信号量。用于实现同步(任务之间或者任务与中断之间)的话,二进制信号量是更好的选择,互斥量用于简单的互锁。

      用于互锁的互斥量可以充当保护资源的令牌。当一个任务希望访问某个资源时,它必须先获取令牌。当任务使用完资源后,必须还回令牌,以便其它任务可以访问同一资源。

      互斥量和信号量使用相同的API函数,因此互斥量也允许指定一个阻塞时间。阻塞时间单位为系统节拍周期时间,数目表示获取互斥量无效时最多处于阻塞状态的系统节拍周期个数。

      互斥量与二进制信号量最大的不同是:互斥量具有优先级继承机制。也就是说,如果一个互斥量(令牌)正在被一个低优先级任务使用,此时一个高优先级企图获取这个互斥量,高优先级任务会因为得不到互斥量而进入阻塞状态,正在使用互斥量的低优先级任务会临时将自己的优先级提升,提升后的优先级与与进入阻塞状态的高优先级任务相同。这个优先级提升的过程叫做优先级继承。这个机制用于确保高优先级任务进入阻塞状态的时间尽可能短,以及将已经出现的“优先级翻转”影响降低到最小。

      在很多场合中,某个硬件资源只有一个,当低优先级任务占用该资源的时候,即便高优先级任务也只能乖乖的等待低优先级任务释放资源。这里高优先级任务无法运行而低优先级任务可以运行的现象称为“优先级翻转”。

      为什么优先级继承能够降低优先级翻转的影响呢?举个例子,现在有任务A、任务B和任务C,三个任务的优先级顺序为任务C>任务B>任务A。任务A和任务C都要使用某一个硬件资源,并且当前任务A占有该资源。

      先看没有优先级继承的情况:任务C也要使用该资源,但是此时任务A正在使用这个资源,因此任务C进入阻塞,此时三个任务的优先级顺序没有发生变化。在任务C进入阻塞之后,某硬件产生了一次中断,唤醒了一个事件,该事件可以解除任务B的阻塞状态。在中断结束后,因为任务B的优先级是大于任务A的,所以任务B抢占任务A的CPU权限。那么任务C的阻塞时间就至少为:中断处理时间+任务B的运行时间+任务A的运行时间。

      再看有优先级继承的情况:任务C也要使用该资源,但是此时任务A正在使用这个资源,因此任务C进入阻塞,此时由于优先级A会继承任务C的优先级,三个任务的优先级顺序发生了变化,新的优先级顺序为:任务C=任务A>任务B。在任务C进入阻塞之后,某硬件产生了一次中断,唤醒了一个事件,该事件可以解除任务B的阻塞状态。在中断结束后,因为任务A的优先级临时被提高,大于任务B的优先级,所以任务A继续获得CPU权限。任务A完成后,处于高优先级的任务C会接管CPU。所以任务C的阻塞时间为:中断处理时间+任务A的运行时间。看,任务C的阻塞时间变小了,这就是优先级继承的优势。

      优先级继承不能解决优先级反转,只能将这种情况的影响降低到最小。硬实时系统在一开始设计时就要避免优先级反转发生。


图4-1 互斥量用于保护资源

      如图4-1所示,互斥量用来保护资源。为了访问资源,任务必须先获取互斥量。任务A想获取资源,首先它使用API函数xSemaphoreTake()获取信号量,成功获取到信号量后,任务A就持有了互斥量,可以安全的访问资源。期间任务B开始执行,它也想访问资源,任务B也要先获得信号量,但是信号量此时是无效的,任务B进入阻塞状态。当任务A执行完成后,使用API函数xSemaphoreGive()释放信号量。之后任务B解除阻塞,任务B使用API函数xSemaphoreTake()获取并得到信号量,任务B可以访问资源。

5.递归互斥量

      已经获取递归互斥量的任务可以重复获取该递归互斥量。使用xSemaphoreTakeRecursive() 函数成功获取几次递归互斥量,就要使用xSemaphoreGiveRecursive()函数返还几次,在此之前递归互斥量都处于无效状态。比如,某个任务成功获取5次递归互斥量,那么在它没有返还5次该递归互斥量之前,这个互斥量对别的任务无效。

      递归互斥量可以看成带有优先级继承机制的信号量,获取递归互斥量的任务在用完后必须返还。

      互斥量不可以用在中断服务程序中,这是因为:

  • 互斥量具有优先级继承机制,只有在任务中获取或给出互斥才有意义。
  • 中断不能因为等待互斥量而阻塞。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458588.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql语法替换字符串

UPDATE ht_business_task SET url REPLACE ( url, &, & )转载于:https://www.cnblogs.com/lz20150121/p/5030739.html

POJ1274 The Perfect Stall(二分图)

题意: 一些奶牛只有在特定的围栏中才能产奶,要求合理安排使能产奶的奶牛数达到最大。 要点: 二分图裸题,最近刚学了二分图,看下面的参考博客,写的比较好: 参考博客:匈牙利算法 15479…

蓝牙HCI剖析(一)

来自:http://blog.csdn.net/xiaoxiaopengbo/article/details/51334257 一.HCI介绍 HCI提供了访问bluetooth control的统一接口,通俗来讲,就是定义了特定的格式来控制蓝牙芯片来做相应的动作(比如inquiry,connect,disconnect&#…

c语言题库2

96. struct name1{ char str; short x; int num; } struct name2{ char str;0 1 2 3 int num; 4 5 6 7 short x; 8 9 10 11 } sizeof(struct name1)? sizeof(struct name2)? 8、12 97. 读文件file1.txt的内容(例如): 12 34 56 …

ASP.NET状缓存Cache的应用-提高数据库读取速度

ASP.NET状缓存Cache的应用-提高数据库读取速度 原文:ASP.NET状缓存Cache的应用-提高数据库读取速度一、 Cache概述 既然缓存中的数据其实是来自数据库的,那么缓存中的数据如何和数据库进行同步呢?一般来说,缓存中应该存放改动不大或者对…

2016年学习Linux决心书(老男孩教育在线课程班第二期)

我经过这4-5个月的学习后,我一定要达到月薪20K,为了达到这个目标我要付出如下10大行动:1.提前预习上课内容2.上课认真听讲,做好上课笔记3.课后认真做总结,完善笔记5.反复做实验,并写实验文档6.学…

WPF XAML 从零开始认识XAML

来自&#xff1a;http://blog.csdn.net/aoshilang2249/article/details/44158403 剖析最简单的XMAL代码: [html] view plaincopy <Window x:Class"MyFirstApplication.MainWindow" xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentati…

c语言题库3

143. 枚举元素本身由系统定义了一个表示序号的数值&#xff0c;从0 开始顺序定义为0&#xff0c;1&#xff0c;2…。如在weekday中&#xff0c;sun值为0&#xff0c;mon值为1&#xff0c; …,sat值为6。 main(){  enum weekday  {   sun,mon,tue,wed,thu,fri,sat  } a,b…

入门级----测试的执行、环境的搭建、每日构建、测试记录和跟踪、回归测试、测试总结和报告...

测试用例的准备&#xff0c;都是为了执行测试准备的。 测试环境的搭建 &#xff08;1&#xff09;测试数据&#xff1a;有些测试需要使用大批量的数据&#xff0c;例如容量测试、压力测试等。根据产品的具体测试要求&#xff0c;可能需要在数据库表插入大量的数据&#xff0c;准…

MFC读取配置文件GetPrivateProfileString

VC中 3 个主要 写入/读取配置文件ini的函数&#xff1a;bool WritePrivateProfileString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTR lpString,LPCTSTR lpFileName);写入.ini文件&#xff1b;DWORDGetPrivateProfileString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTR lpD…

UESTC 250 windy数 数位dp

题目链接 1 #include<bits/stdc.h>2 using namespace std;3 #define mem1(a) memset(a, -1, sizeof(a))4 #define ll long long5 int dp[20][20], digit[20], len;6 ll dfs(int len, int pre, bool fp, bool first) { //first表示前面的数是否全部为0&#xff0c; pr…

c语言面试题大全

C语言面试题大汇总 4. static有什么用途&#xff1f;&#xff08;请至少说明两种&#xff09; 1.限制变量的作用域(DL:使其只在定义的当前文件中起作用&#xff0c;static是只能由与变量在同一个文件中定义的程序存取的全局变量。也就是说使全局变量成为文件的私有变量&#…

WindowsAPI详解——GetCurrentDirectory 获得程序当前目录

每个Windows程序都有一个自己的当前目录&#xff0c;默认是程序exe文件所在的目录。系统在给程序加载动态链接库文件(DLL)时先在程序当前目录里查找要加载的DLL&#xff0c;如果在此目录下没有找到系统便会去Windows目录下查找。在这儿我们主要将如何获得程序的当前目录&#x…

20151210小问题2

1、各浏览器下 scrollTop的差异 IE6/7/8&#xff1a; 对于没有doctype声明的页面里可以使用 document.body.scrollTop 来获取 scrollTop高度 &#xff1b; 对于有doctype声明的页面则可以使用 document.documentElement.scrollTop&#xff1b; Safari: safari 比较特别&#x…

限制MySQL Binlog的传输速率

最近一台核心库备库完成恢复后打开slave&#xff0c;导致主库传送binlog&#xff0c;瞬间占满网络&#xff0c;触发故障。 为了做一些限制&#xff0c; 给mysql在发送binlog的函数(mysql_binlog_send)里每隔一段时间sleep一次&#xff0c; 增加了两个参数&#xff1a; master_s…

sprintf用法详解

printf可能是许多程序员在开始学习C语言时接触到的第二个函数&#xff08;我猜第一个是main&#xff09;&#xff0c;说起来&#xff0c;自然是老朋友了&#xff0c;可是&#xff0c;你对这个老朋友了解多吗&#xff1f;你对它的那个孪生兄弟sprintf了解多吗&#xff1f;在将各…

掌握 Ajax,第 2 部分: 使用 JavaScript 和 Ajax 发出异步请求

转http://www.ibm.com/developerworks/cn/xml/wa-ajaxintro2/ 掌握 Ajax&#xff0c;第 2 部分: 使用 JavaScript 和 Ajax 发出异步请求 在 Web 请求中使用 XMLHttpRequest 多数 Web 应用程序都使用请求/响应模型从服务器上获得完整的 HTML 页面。常常是点击一个按钮&#xff0…

Provisioning Services 7.8 入门系列教程之十一 通过版本控制自动更新虚拟磁盘

续Provisioning Services 7.8 入门系列教程之十 通过类自动更新虚拟磁盘从前两的两种更新方式可以看出&#xff0c;它们有一个共同的特点&#xff0c;即需要产生&#xff08;复制&#xff09;完成的虚拟磁盘副本&#xff0c;然后进行相关的升级操作。这两种方法在实际生产中&am…

OC面试题

什么是KVC和KVO&#xff1f; 答&#xff1a;KVC(Key-Value-Coding)内部的实现&#xff1a;一个对象在调用setValue的时候&#xff0c; &#xff08;1&#xff09;首先根据方法名找到运行方法的时候所需要的环境参数。 &#xff08;2&#xff09;他会从自己isa指针结合环境参数&…

【算法】QuickSort

快速排序&#xff0c;时间复杂度O(N*logN)&#xff0c;要能熟练掌握&#xff01; 以下主要参考http://blog.csdn.net/morewindows/article/details/6684558&#xff0c; 感谢原博主&#xff01; 该方法的基本思想是&#xff1a; 1&#xff0e;先从数列中取出一个数作为基准数。…