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

相关文章

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

C#控制台程序同步调用WebApi实现方式

《C#控制台程序同步调用WebApi实现方式》控制台程序作为Job时,需同步调用WebApi以确保获取返回结果后执行后续操作,否则会引发TaskCanceledException异常,同步处理可避免异... 目录同步调用WebApi方法Cls001类里面的写法总结控制台程序一般当作Job使用,有时候需要控制

SpringBoot实现虚拟线程的方案

《SpringBoot实现虚拟线程的方案》Java19引入虚拟线程,本文就来介绍一下SpringBoot实现虚拟线程的方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录什么是虚拟线程虚拟线程和普通线程的区别SpringBoot使用虚拟线程配置@Async性能对比H

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

Linux线程同步/互斥过程详解

《Linux线程同步/互斥过程详解》文章讲解多线程并发访问导致竞态条件,需通过互斥锁、原子操作和条件变量实现线程安全与同步,分析死锁条件及避免方法,并介绍RAII封装技术提升资源管理效率... 目录01. 资源共享问题1.1 多线程并发访问1.2 临界区与临界资源1.3 锁的引入02. 多线程案例2.1 为

Java中的xxl-job调度器线程池工作机制

《Java中的xxl-job调度器线程池工作机制》xxl-job通过快慢线程池分离短时与长时任务,动态降级超时任务至慢池,结合异步触发和资源隔离机制,提升高频调度的性能与稳定性,支撑高并发场景下的可靠... 目录⚙️ 一、调度器线程池的核心设计 二、线程池的工作流程 三、线程池配置参数与优化 四、总结:线程

WinForm跨线程访问UI及UI卡死的解决方案

《WinForm跨线程访问UI及UI卡死的解决方案》在WinForm开发过程中,跨线程访问UI控件和界面卡死是常见的技术难题,由于Windows窗体应用程序的UI控件默认只能在主线程(UI线程)上操作... 目录前言正文案例1:直接线程操作(无UI访问)案例2:BeginInvoke访问UI(错误用法)案例

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

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