专业网站推广的公司哪家好,推销产品怎样才能打动客户,竞价排名点击器,成都网站优化外包来自#xff1a;http://blog.csdn.net/zhzht19861011/article/details/50835613 本文介绍信号量的基础知识#xff0c;详细源码分析见《FreeRTOS高级篇6---FreeRTOS信号量分析》 1.信号量简介 FreeRTOS的信号量包括二进制信号量、计数信号量、互斥信号量#xff08;以后简称… 来自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。因此计数值是事件发生的数量和事件处理的数量差值。在这种情况下计数信号量在创建时其值为0。资源管理这种用法下计数值表示有效的资源数目。任务必须先获取信号量才能获取资源控制权。当计数值减为零时表示没有的资源。当任务完成后它会返还信号量---信号量计数值增加。在这种情况下信号量创建时计数值等于最大资源数目。 注中断程序中决不可使用无“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次该递归互斥量之前这个互斥量对别的任务无效。 递归互斥量可以看成带有优先级继承机制的信号量获取递归互斥量的任务在用完后必须返还。 互斥量不可以用在中断服务程序中这是因为 互斥量具有优先级继承机制只有在任务中获取或给出互斥才有意义。中断不能因为等待互斥量而阻塞。