FreeRTOS入门教程(信号量的概念及API函数使用)

简介: FreeRTOS入门教程(信号量的概念及API函数使用)

前言

本篇文章正式带大家开始学习什么是信号量,并且掌握信号量函数的基本使用方法,并且将和队列进行一个对比。

一、什么是信号量

FreeRTOS 中的信号量是一种用于任务间同步和互斥的机制。它允许任务在临界区保护资源的访问、线程间通信以及任务之间的同步操作。信号量可以用来保护共享资源,限制对资源的并发访问,以及进行任务间的事件通知。

二、信号量种类和对比

FreeRTOS 提供了两种类型的信号量:二值信号量(Binary Semaphore)和计数型信号量(Counting Semaphore)。

二值信号量(Binary Semaphore):

二值信号量是最简单的一种信号量,它只能有两个状态:0 和 1。它常用于互斥访问共享资源的情况,如保护共享数据结构、保证一次只有一个任务执行临界区等。任务可以通过获取或释放二值信号量来请求或释放对共享资源的访问。

创建二值信号量使用 xSemaphoreCreateBinary 函数,并通过 xSemaphoreGive 和 xSemaphoreTake 函数来释放和获取信号量。

计数型信号量(Counting Semaphore):

计数型信号量可以有多个状态值,允许多个任务同时访问共享资源,可以用于控制资源的可用性。计数型信号量常用于限制任务的并发执行数量,或者用于任务间的生产者-消费者模型等场景。

创建计数型信号量使用 xSemaphoreCreateCounting 函数,并通过 xSemaphoreGive 和 xSemaphoreTake 函数来增加和减少信号量的计数值。

在使用信号量时,任务通过获取信号量来尝试占用资源,并在未能获取时阻塞等待。一旦资源可用或条件满足,任务释放信号量,让其他任务可以获取资源或继续执行。这样可以确保对共享资源的安全性和正确性。

需要注意的是,使用信号量时要小心处理同步和互斥问题,以避免竞态条件和死锁。此外,信号量的使用应该遵循良好的软件设计原则,以避免过度使用和滥用信号量。

二种信号量的对比:

1.功能:

二值信号量(Binary Semaphore):只有两个状态,0 和 1。主要用于互斥访问共享资源的情况,保护共享数据结构,限制对资源的并发访问。一般用于排它性操作,尽量保持资源独占一个任务操作。

计数型信号量(Counting Semaphore):可以有多个状态值,用于控制资源的可用性。可用于限制并发执行数量、任务间的生产者-消费者模型等场景。

2.创建和初始化:

二值信号量:可以使用 xSemaphoreCreateBinary 函数创建,并使用 xSemaphoreGive 进行初始化,调用 xSemaphoreTake 来获取信号量。

计数型信号量:可以使用 xSemaphoreCreateCounting 函数创建,并使用 xSemaphoreGive 进行初始化,调用 xSemaphoreTake 来获取信号量。

3.值的范围:

二值信号量:具有两个状态,0 和 1。只能通过 xSemaphoreGive 和 xSemaphoreTake 将其值从 0 切换到 1 或者从 1 切换到 0。

计数型信号量:具有更大的范围,可以从 0 到一个设定的最大数值之间进行计数。

4.使用场景:

二值信号量:适用于互斥访问共享资源的场景,例如保护共享数据结构、保证一次只有一个任务执行临界区等。

计数型信号量:适用于控制并发执行数量的场景,或者用于任务间的生产者-消费者模型等

三、信号量和队列的区别

1.功能:

信号量:信号量是一种用于任务间同步和互斥的机制。它可以用于保护共享资源、限制并发访问、控制任务的执行顺序等。信号量具有两种类型:二值信号量和计数型信号量。

队列:队列是一种用于任务间传递数据的机制。它允许任务按照先进先出(FIFO)的顺序共享数据。任务可以将数据发送到队列,并从队列接收数据。队列的长度限制了可以在其中排队的数据项的数量。

2.数据传输方式:

信号量:信号量一般用于同步和互斥,不直接传输数据。通过获取和释放信号量来控制任务对资源的访问。二值信号量和计数型信号量的获取和释放操作可以用来表示任务的事件和计数。

队列:队列用于任务间传递数据。任务通过发送和接收操作将数据项从一个任务传递到另一个任务。发送操作将数据项复制到队列中,接收操作将数据项从队列中复制到接收任务的缓冲区中。

3.数据复制:

信号量:信号量在任务间的数据共享过程中通常不涉及数据复制。它们通常用于任务间对资源的访问控制,而不是实际的数据传输。二值信号量和计数型信号量是通过操作信号量的计数值来控制任务的行为。

队列:队列在任务间传递数据时涉及数据的复制。发送任务向队列发送数据项时,数据项的副本将存储在队列中。接收任务从队列接收数据项时,队列将数据项的副本复制到接收任务的缓冲区中。

4.用途:

信号量:信号量在需要任务进行同步和互斥的场景下非常有用。例如,保护共享资源、控制并发访问、任务的事件通知等。

队列:队列在需要任务间传递数据的场景下非常有用。例如,实现生产者-消费者模型、任务间的消息传递、任务间的数据通信等。

综上所述,信号量主要用于同步和互斥,控制任务对资源的访问。它们不直接传输数据,而是控制任务的行为。队列则用于任务间传递数据,按照先进先出的顺序共享数据项。选择使用信号量还是队列取决于需求,如任务间的数据传输、共享资源的访问控制,以及任务的同步需求。

四、信号量相关的函数

1.创建函数

创建二值信号量函数:

xSemaphoreCreateBinary 函数原型:

SemaphoreHandle_t xSemaphoreCreateBinary( void );

参数:无

返回值:SemaphoreHandle_t,一个二值信号量的句柄。

创建计数信号量函数:

xSemaphoreCreateCounting 函数原型:

SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount );

参数:

uxMaxCount:信号量的最大计数值,即最多可以计数到多少。

uxInitialCount:信号量的初始计数值,通常为 0。

返回值:SemaphoreHandle_t,一个计数型信号量的句柄。

2.删除函数

void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

参数:

xSemaphore:要删除的信号量的句柄。

要注意的是,删除一个信号量前,请确保没有任务正在等待该信号量,否则可能导致未定义的行为。在删除信号量之前,可以使用 uxSemaphoreGetCount 函数来获取当前信号量的计数值,以确保没有任务在等待。

3.获取和释放信号量函数

获取信号量函数:

xSemaphoreGive 函数原型:

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

参数:

xSemaphore:信号量的句柄。

返回值:如果成功释放信号量,则返回 pdPASS(1),否则返回 pdFAIL(0)。

中断中释放信号量函数:

xSemaphoreGiveFromISR 函数原型:

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );

xSemaphore:信号量的句柄。

pxHigherPriorityTaskWoken:一个指向 BaseType_t 类型的变量的指针,用于指示在 ISR 中调用时是否唤醒了更高优先级的任务。

返回值:如果成功释放信号量,则返回 pdPASS(1),否则返回 pdFAIL(0)。

xSemaphoreGive 函数原型:

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

参数:

xSemaphore:信号量的句柄。

返回值:如果成功释放信号量,则返回 pdPASS(1),否则返回 pdFAIL(0)。

总结

本篇文章主要讲解了信号量的概念及API函数使用,大家看完后可以做个总结,并进行对应的实验。


相关文章
|
2月前
|
缓存 JavaScript 算法
活用 Composition API 核心函数,打造卓越应用(下)
活用 Composition API 核心函数,打造卓越应用(下)
|
2月前
|
存储 JavaScript API
活用 Composition API 核心函数,打造卓越应用(上)
活用 Composition API 核心函数,打造卓越应用(上)
|
3月前
|
机器学习/深度学习 API 开发工具
通义千问API入门教程
本教程将带你从零开始,快速了解如何通过 API 使用通义千问大模型,并尝试使用大模型 API 开发一些简单的应用应用到工作中,提升效率。
13663 10
|
2月前
|
人工智能 关系型数据库 Serverless
Serverless 应用引擎常见问题之API生成的函数镜像改为自定义的镜像如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
39 3
|
6天前
|
Java 大数据 API
[AIGC] Flink入门教程:理解DataStream API(Java版)
[AIGC] Flink入门教程:理解DataStream API(Java版)
|
14天前
|
JavaScript API
Vue3 API函数及功能
Vue3 API函数及功能
7 0
|
2月前
|
存储 安全 Linux
【Linux 创建临时文件 API】编程中的瞬息之光:临时文件的艺术与智慧 tmpnam,tmpfile,mkstemp,mkdtemp等函数解析...
【Linux 创建临时文件 API】编程中的瞬息之光:临时文件的艺术与智慧 tmpnam,tmpfile,mkstemp,mkdtemp等函数解析...
24 0
|
2月前
|
数据库连接 API 数据库
SQLite3 数据库 C语言API 打开函数sqlite3_open 详解
SQLite3 数据库 C语言API 打开函数sqlite3_open 详解
44 0
|
2月前
|
编译器 API C++
【C++ 动态库设计】动态库中的模板函数:解决如果将模板函数封装成API库
【C++ 动态库设计】动态库中的模板函数:解决如果将模板函数封装成API库
50 0
|
2月前
|
Java 数据库连接 API
Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API
Java 是一种广泛使用的、面向对象的编程语言,始于1995年,以其跨平台性、安全性和可靠性著称,应用于从移动设备到数据中心的各种场景。基础概念包括变量(如局部、实例和静态变量)、数据类型(原始和非原始)、条件语句(if、else、switch等)、函数、循环、异常处理、数据结构(如数组、链表)和面向对象编程(类、接口、继承等)。深入学习还包括包、内存管理、集合框架、序列化、网络套接字、泛型、流、JVM、垃圾回收和线程。构建工具如Gradle、Maven和Ant简化了开发流程,Web框架如Spring和Spring Boot支持Web应用开发。ORM工具如JPA、Hibernate处理对象与数
95 3