FreeRTOS线程同步1---信号量

2024-09-03 03:44

本文主要是介绍FreeRTOS线程同步1---信号量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

二值信号量

二值信号量相关API函数

一般使用方法为

1.创建二值信号量

2.在一个任务中置为二值释放信号

3.在另一个任务中获取信号

计数信号量

计数型信号量相关 API 函数

使用方法

1.创建计数信号量

2.释放计数信号量

3.获得信号量的当前值

4.释放信号量

互斥信号量

互斥信号量常用API函数

使用方法


        信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。其中,“同步”指的
是任务间的同步,即信号量可以使得一个任务等待另一个任务完成某件事情后,才继续执行;
而“有序访问”指的是对被多任务或中断访问的共享资源(如全局变量)的管理,当一个任务
在访问(读取或写入)一个共享资源时,信号量可以防止其他任务或中断在这期间访问(读取
或写入)这个共享资源。

        需要包含的头文件为"semphr.h "

二值信号量

        信号量是基于队列实现的,二值信号量也不例外,二值信号量实际上就是一个队列长度为 1 的队列,在这种情况下,队列就只有空和满两种情况,这不就是二值情况吗。

事实上RTOS正是这样做的:

在创建二值信号量的函数xSemaphoreCreateBinaryStatic( )里跳转进入可以看到它是一个宏定义,会在预处理阶段直接替换为xQueueGenericCreateStatic( )静态创建了一个大小为1的队列

#if ( configSUPPORT_STATIC_ALLOCATION == 1 )#define xSemaphoreCreateBinaryStatic( pxStaticSemaphore )    xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, ( pxStaticSemaphore ), queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif /* configSUPPORT_STATIC_ALLOCATION */

二值信号量相关API函数

函数
描述
xSemaphoreCreateBinary()
使用动态方式创建 二值信号量
xSemaphoreCreateBinaryStatic()
使用静态方式创建二值信号量
xSemaphoreTake()
获取信号量
xSemaphoreTakeFromISR().
在中断中获取信号量
xSemaphoreGive()
释放信号量
xSemaphoreGiveFromISR()
在中断中释放信号量
vSemaphoreDelete()
删除信号量

一般使用方法为

1.创建二值信号量
QueueHandle_t xSemaphore;//声明二值信号量
xSemaphore = xSemaphoreCreateBinary();//创建二值信号量
2.在一个任务中置为二值释放信号
xSemaphoreGive(xSemaphore);//释放信号
3.在另一个任务中获取信号
xSemaphoreTake(xSemaphore, portMAX_DELAY);//获得信号量

注意在等待信号量的任务中应该为

while(1){if(xSemaphoreTake(xSemaphore, portMAX_DELAY);//阻塞等待{... /*具体操作*/}
}

从而达到任务阻塞等待信号的作用

计数信号量

        计数型信号量与二值信号量类似,二值信号量相当于队列长度为 1 的队列,因此二值信号
量只能容纳一个资源,这也是为什么命名为二值信号量,而计数型信号量相当于队列长度大于
0 的队列,因此计数型信号量能够容纳多个资源,这是在计数型信号量被创建的时候确定的。
计数型信号量通常用于一下两种场合:
1. 事件计数
        每次事件发生后,在事件处理函数中释放计数型信号量(计数型信号量的
资源数加 1),其他等待事件发生的任务获取计数型信号量(计数型信号量的资源数减 1),这么
一来等待事件发生的任务就可以在成功获取到计数型信号量之后执行相应的操作。在这种场合
下,计数型信号量的资源数一般在创建时设置为 0。
2. 资源管理
        计数型信号量的资源数代表着共享资源的可用数量,例如前面举例中停车
场中的空车位。一个任务想要访问共享资源,就必须先获取这个共享资源的计数型信号量,之
后在成功获取了计数型信号量之后,才可以对这个共享资源进行访问操作,当然,在使用完共
享资源后也要释放这个共享资源的计数型信号量。在这种场合下,计数型信号量的资源数一般
在创建时设置为受其管理的共享资源的最大可用数量。

计数型信号量相关 API 函数

函数
描述
xSemaphoreCreateCounting()
使用动态方式创建计数型信号量
xSemaphoreCreateCountingStatic()
使用静态方式创建计数型信号量
xSemaphoreTake()
获取信号量
xSemaphoreTakeFromISR()
在中断中获取信号量
xSemaphoreGive()
释放信号量
xSemaphoreGiveFromISR()
在中断中释放信号量
vSemaphoreDelete()
删除信号量

使用方法

1.创建计数信号量
QueueHandle_t CountSemaphore;/声明计数信号量
CountSemaphore=xSemaphoreCreateCounting( (UBaseType_t)255, (UBaseType_t)0);
/*计数信号量最大255,初始为0*/
2.释放计数信号量
/* 释放计数型信号量 */
xSemaphoreGive(CountSemaphore);
3.获得信号量的当前值
uint32_t semaphore_val = uxSemaphoreGetCount(CountSemaphore);//获得信号量值
printf("当前计数信号量%d\r\n",semaphore_val);
4.释放信号量
xSemaphoreTake(CountSemaphore,(TickType_t )portMAX_DELAY);//阻塞最大时间portMAX_DELAY

互斥信号量

        互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中(任务与任务或
中断与任务之间的同步)二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中。
在互斥访问中互斥信号量相当于一把钥匙,当任务想要访问共享资源的时候就必须先获得这把
钥匙,当访问完共享资源以后就必须归还这把钥匙,这样其他的任务就可以拿着这把钥匙去访
问资源。

        首先要介绍以下实时性问题里的”优先级翻转“

        优先级翻转的示例中,,任务 H 为最高优先级的任务,因此任务 H 执行的操作需要有较高的实时性,但是由于优先级翻转的问题,导致了任务 H 需要等到任务 L 释放信号量才能够运行,并且,任务 L 还会被其他介于任务 H 与任务 L 任务优先级之间的任务 M 抢占,因此任务 H 还需等待任务 M 运行完毕,这显然不符合任务 H 需要的高实时性要求。

        然而互斥信号量的特性中优先级继承,优先级继承尽可能的减少了高优先级任务处于阻塞态
的时间,并且将“优先级翻转”的影响降到最低。

        优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的
影响。实时应用应该在设计之初就要避免优先级翻转的发生。互斥信号量不能用于中断服务函
数中
,原因如下:
(1) 互斥信号量有任务优先级继承的机制,但是中断不是任务,没有任务优先级,所以互斥
信号量只能用与任务中,不能用于中断服务函数。
(2) 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。

互斥信号量常用API函数
函数
描述
xSemaphoreCreateMutex()
使用动态方式创建互斥信号量
xSemaphoreCreateMutexStatic()
使用静态方式创建互斥信号量
xSemaphoreTake()
获取信号量
xSemaphoreGive()
释放信号量
vSemaphoreDelete()
删除信号量

        从上面中可以看出,互斥信号量除了创建函数之外,其余的获取、释放等信号量操作函数,
都与二值信号量相同。

使用方法

        同二值信号量

这篇关于FreeRTOS线程同步1---信号量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131927

相关文章

Spring Boot3虚拟线程的使用步骤详解

《SpringBoot3虚拟线程的使用步骤详解》虚拟线程是Java19中引入的一个新特性,旨在通过简化线程管理来提升应用程序的并发性能,:本文主要介绍SpringBoot3虚拟线程的使用步骤,... 目录问题根源分析解决方案验证验证实验实验1:未启用keep-alive实验2:启用keep-alive扩展建

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步

Java终止正在运行的线程的三种方法

《Java终止正在运行的线程的三种方法》停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作,停止一个线程可以用Thread.stop()方法,但最好不要用它,本文给大家介绍了... 目录前言1. 停止不了的线程2. 判断线程是否停止状态3. 能停止的线程–异常法4. 在沉睡中停止5

Java捕获ThreadPoolExecutor内部线程异常的四种方法

《Java捕获ThreadPoolExecutor内部线程异常的四种方法》这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感... 目录方案 1方案 2方案 3方案 4结论方案 1使用 execute + try-catch 记录

Linux搭建Mysql主从同步的教程

《Linux搭建Mysql主从同步的教程》:本文主要介绍Linux搭建Mysql主从同步的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux搭建mysql主从同步1.启动mysql服务2.修改Mysql主库配置文件/etc/my.cnf3.重启主库my

Spring Boot 中正确地在异步线程中使用 HttpServletRequest的方法

《SpringBoot中正确地在异步线程中使用HttpServletRequest的方法》文章讨论了在SpringBoot中如何在异步线程中正确使用HttpServletRequest的问题,... 目录前言一、问题的来源:为什么异步线程中无法访问 HttpServletRequest?1. 请求上下文与线

在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

Java中将异步调用转为同步的五种实现方法

《Java中将异步调用转为同步的五种实现方法》本文介绍了将异步调用转为同步阻塞模式的五种方法:wait/notify、ReentrantLock+Condition、Future、CountDownL... 目录异步与同步的核心区别方法一:使用wait/notify + synchronized代码示例关键

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

java父子线程之间实现共享传递数据

《java父子线程之间实现共享传递数据》本文介绍了Java中父子线程间共享传递数据的几种方法,包括ThreadLocal变量、并发集合和内存队列或消息队列,并提醒注意并发安全问题... 目录通过 ThreadLocal 变量共享数据通过并发集合共享数据通过内存队列或消息队列共享数据注意并发安全问题总结在 J