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

相关文章

Linux线程之线程的创建、属性、回收、退出、取消方式

《Linux线程之线程的创建、属性、回收、退出、取消方式》文章总结了线程管理核心知识:线程号唯一、创建方式、属性设置(如分离状态与栈大小)、回收机制(join/detach)、退出方法(返回/pthr... 目录1. 线程号2. 线程的创建3. 线程属性4. 线程的回收5. 线程的退出6. 线程的取消7.

Linux下进程的CPU配置与线程绑定过程

《Linux下进程的CPU配置与线程绑定过程》本文介绍Linux系统中基于进程和线程的CPU配置方法,通过taskset命令和pthread库调整亲和力,将进程/线程绑定到特定CPU核心以优化资源分配... 目录1 基于进程的CPU配置1.1 对CPU亲和力的配置1.2 绑定进程到指定CPU核上运行2 基于

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

SpringBoot线程池配置使用示例详解

《SpringBoot线程池配置使用示例详解》SpringBoot集成@Async注解,支持线程池参数配置(核心数、队列容量、拒绝策略等)及生命周期管理,结合监控与任务装饰器,提升异步处理效率与系统... 目录一、核心特性二、添加依赖三、参数详解四、配置线程池五、应用实践代码说明拒绝策略(Rejected

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

Java中常见队列举例详解(非线程安全)

《Java中常见队列举例详解(非线程安全)》队列用于模拟队列这种数据结构,队列通常是指先进先出的容器,:本文主要介绍Java中常见队列(非线程安全)的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一.队列定义 二.常见接口 三.常见实现类3.1 ArrayDeque3.1.1 实现原理3.1.2

SpringBoot3中使用虚拟线程的完整步骤

《SpringBoot3中使用虚拟线程的完整步骤》在SpringBoot3中使用Java21+的虚拟线程(VirtualThreads)可以显著提升I/O密集型应用的并发能力,这篇文章为大家介绍了详细... 目录1. 环境准备2. 配置虚拟线程方式一:全局启用虚拟线程(Tomcat/Jetty)方式二:异步