前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >FreeRTOS | 信号量(第十四天)

FreeRTOS | 信号量(第十四天)

原创
作者头像
Qt历险记
发布2024-11-04 20:19:22
发布2024-11-04 20:19:22
14700
代码可运行
举报
文章被收录于专栏:嵌入式软件
运行总次数:0
代码可运行

点击上方"蓝字"关注我们

00、上节回顾

RTOS | 那么什么是RTOS?三大操作系统?(第十四天)

FreeRTOS | 原理介绍和资源get(第十四天)

FreeRTOS | STM32F407 FreeRTOS移植(第十四天)

FreeRTOS | 任务管理(第十四天)

FreeRTOS | 内核控制函数和时间管理(第十四天)

FreeRTOS | 开中断与临界区(第十四天)

01、概述

>>>信号量,Semaphore:英[ˈseməfɔː(r)]。 信号量常用于任务的同步,通过该信号,就能够控制某个任务的执行,这个信号具有计数值,因此,可以称为计数信号量。 计数信号量可以用于资源管理,允许多个任务获取信号量访问共享资源,但会限制任务的最大数目。访问的任务数达到可支持的最大数目时,会阻塞其他试图获取该信号量的任务,直到有任务释放了信号量。这就是计数型信号量的运作机制,虽然计数信号量允许多个任务访问同一个资源,但是也有限定,比如某个资源限定只能有3个任务访问,那么第4个任务访问的时候,会因为获取不到信号量而进入阻塞,等到有任务(比如任务1)释放掉该资源的时候,第4个任务才能获取到信号量从而进行资源的访问,其运作的机制具体见下图。

图1 计数信号量运作示意图 生活中常见的例子,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。

图2 实际停车场 在这个停车场系统中,车位是公共资源,每辆车好比一个任务(线程),看门人起的就是控制信号量的作用,描述车位数。

02、PV原语

>>>

1965年,荷兰学者Dijkstra提出了利用信号量机制解决进程同步问题,信号量正式成为有效的进程同步工具,现在信号量机制被广泛的用于单处理机和多处理机系统以及计算机网络中。 信号量S是一个整数,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用临界区的进程数。 Dijkstra同时提出了对信号量操作的PV原语。 P原语操作的动作是:   (1)S减1;   (2)若S减1后仍大于或等于零,则进程继续执行;   (3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。 V原语操作的动作是:   (1)S加1;   (2)若相加结果大于零,则进程继续执行;   (3)若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。 PV操作对于每一个进程来说,都只能进行一次,而且必须成对使用。在PV原语执行期间不允许有中断的发生。 信号量的P、V操作,P表示申请一个资源,每次P操作使信号量减1,V是释放一个资源,每次V操作使信号量加1。信号量表示的是当前可用的资源个数,当信号量为负时,申请资源的进程(任务)就只能等待了。所以,信号量是负的多少,就表明有多少个进程(任务)申请了资源但无资源可用,只能处于等待状态。 除了访问共享资源外,亦可中断/任务控制某任务的执行,称之为“单向同步”。

代码语言:javascript
代码运行次数:0
复制
// 文件路径:freertos.h​#ifndef configUSE_COUNTING_SEMAPHORES  #define configUSE_COUNTING_SEMAPHORES 1​#endif​

03、函数接口

>>> 1.创建一个计数信号量 SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount); 参数说明: uxMaxCount-计数信号量的最大值,当达到这个值的时候,信号量不能再被释放。 uxInitialCount-创建计数信号量的初始值。 返回值: 如果创建成功则返回一个计数信号量句柄,用于访问创建的计数信号量。如果创建不成功则返回 NULL。 2.创建一个二值信号量 SemaphoreHandle_t xSemaphoreCreateBinary(void); 返回值NULL:二值信号量创建失败 其它值:创建成功的二值信号量的句柄

>>> 3.信号量释放 xSemaphoreGive()是一个用于释放信号量的宏,真正的实现过程是调用消息队列通用发送函数。释放的信号量对象必须是已经被创建的,可以用于二值信号量、计数信号量、互斥量的释放,但不能释放由函数xSemaphoreCreateRecursiveMutex()创建的递归互斥量。此外该函数不能在中断中使用。

代码语言:javascript
代码运行次数:0
复制
#define xSemaphoreGive( xSemaphore ) \  xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), \​NULL, \​semGIVE_BLOCK_TIME, \​queueSEND_TO_BACK )​​

4.获取一个信号量,可以是二值信号量、计数信号量、互斥量。 xSemaphoreTake()函数用于获取信号量,不带中断保护。获取的信号量对象可以是二 值信号量、计数信号量和互斥量,但是递归互斥量并不能使用这个 API 函数获取。其实获 取信号量是一个宏,真正调用的函数是 xQueueGenericReceive ()。该宏不能在中断使用, 而是必须由具体中断保护功能的 xQueueReceiveFromISR()版本代替。

代码语言:javascript
代码运行次数:0
复制
#define xSemaphoreTake( xSemaphore, xBlockTime )  xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), ​  NULL,   ( xBlockTime ),   pdFALSE )​

>>> 参数说明xSemaphore-信号量句柄。 xBlockTime -等待信号量可用的最大超时时间,单位为 tick(即系统节拍周期)。 如果宏 INCLUDE_vTaskSuspend 定义为 1 且形参 xTicksToWait 设置为 portMAX_DELAY ,则任务将一直阻塞在该信号量上(即没有超时时间)。 返回值:获取成功则返回pdTRUE,在指定的超时时间中没有获取成功则返回errQUEUE_EMPTY。 从该宏定义可以看出释放信号量实际上是一次消息出队操作,阻塞时间由用户指定xBlockTime,当有任务试图获取信号量的时候,当且仅当信号量有效的时候,任务才能读获取到信号量。如果信号量无效,在用户指定的阻塞超时时间中,该任务将保持阻塞状态以等待信号量有效。当其它任务或中断释放了有效的信号量,该任务将自动由阻塞态转移为就绪态。当任务等待的时间超过了指定的阻塞时间,即使信号量中还是没有可用信号量,任务也会自动从阻塞态转移为就绪态。

>>> 5.在中断释放信号量 用于释放一个信号量,带中断保护。被释放的信号量可以是二进制信号量和计量。

代码语言:javascript
代码运行次数:0
复制
#define xSemaphoreGiveFromISR( xSemaphore, \​pxHigherPriorityTaskWoken ) \  xQueueGiveFromISR(( QueueHandle_t ) \  ( xSemaphore ), \  ( pxHigherPriorityTaskWoken ) )​​

>>> 6.在中断获取一个信号量,可以是二值信号量、计数信号量 xSemaphoreTakeFromISR()是函数 xSemaphoreTake()的中断版本,用于获取信号量,是 一个不带阻塞机制获取信号量的函数,获取对象必须由是已经创建的信号量,信号量类型 可以是二值信号量和计数信号量,它与 xSemaphoreTake()函数不同,它不能用于获取互斥xSemaphoreTake()函数不同,它不能用于获取互斥量,因为互斥量不可以在中断中使用,并且互斥量特有的优先级继承机制只能在任务中起 作用,而在中断中毫无意义。 xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken) 功能描述:在中断中获一个信号量(其实很少在中断中获取信号量)。可以是二值信号量、计数信号量。 参数说明xSemaphore-信号量句柄。 pxHigherPriorityTaskWoken-一个或者多个任务有可能阻塞在同一个信号量上,调用函数 xSemaphoreTakeFromISR()会唤醒阻塞在该信号量上优先级最高的信号量入队任务,如果被唤醒的任务的优 先级大于或者等于被中断的任务的优先级,那么形参 pxHigherPriorityTaskWoken 就会被设置为 pdTRUE,然后 在中断退出前执行一次上下文切换,中断退出后则直接返回刚刚被唤醒的高优先级的任务。从 FreeRTOS V7.3.0 版本开始,pxHigherPriorityTaskWoken 是一个可选的参数,可以设置为 NULL。 返回值:获取成功则返回 pdTRUE,没有获取成功则返回 errQUEUE_EMPTY,没有获取成功是因为信号量不可用。

04、示例代码

>>> 二值型信号量

实际工作如果需要,但是又不熟悉,第一多看官方文档。第二看书实操,记忆更加深刻。

总结 目前已分享内容

>>>通过网盘分享的文件:FreeRTOS 链接: https://pan.baidu.com/s/1B78HgLtU2vfKi5j4Z_u30A?pwd=nt7z 提取码: nt7z

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 00、上节回顾
  • 01、概述
  • 02、PV原语
  • 03、函数接口
  • 04、示例代码
  • 总结 目前已分享内容
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档