💌 所属专栏:【BES2500x系列】
😀 作 者:我是夜阑的狗🐶
🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询!
💖 欢迎大家:这里是CSDN,我总结知识的地方,喜欢的话请三连,有问题请私信 😘 😘 😘
您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!🤩 🤩 🤩
文章目录
- 前言
- 1 介绍
- 2 功能特性
- 3 同步与通信
- 3.1 同步(Synchronization)
- 3.2 设计原则
- 3.3 实例应用
- 4 信号量
- 4.1 定义信号量
- 4.1.1 代码
- 4.1.2 参数/函数讲解
- 4.2 创建信号量
- 4.2.1 代码
- 4.2.2 参数/函数讲解
- 4.3 获取信号量
- 4.3.1 代码
- 4.3.2 参数/函数讲解
- 4.4 释放信号量
- 4.4.1 代码
- 4.4.2 参数/函数讲解
- 5 互斥锁
- 5.1 定义
- 5.1.1 代码
- 5.1.2 参数/函数讲解
- 5.2 创建
- 5.2.1 代码
- 5.2.2 参数/函数讲解
- 5.3 加锁
- 5.3.1 代码
- 5.3.2 参数/函数讲解
- 5.4 解锁
- 5.4.1 代码
- 5.4.2 参数/函数讲解
- 总结
前言
大家好,又见面了,我是夜阑的狗🐶,本文是专栏【BES2500x系列】专栏的第21篇文章;
今天开始学习BES2500x系列的一天💖💖💖,开启新的征程,记录最美好的时刻🎉,每天进步一点点。
专栏地址:【BES2500x系列】, 此专栏是我是夜阑的狗对BES2500x系列开发过程的总结,希望能够加深自己的印象,以及帮助到其他的小伙伴😉😉。
如果文章有什么需要改进的地方还请大佬不吝赐教👏👏。
1 介绍
前面已经学习了 RTX 系统中线程管理的创建和使用,当然在操作系统中除了线程管理外,线程之间的同步与通信也是至关重要的,话不多说,那接下来就同步与通信都有那些内容吧,让我们原文再续,书接上回吧。
2 功能特性
在实时操作系统(RTOS)中,任务管理和同步通信是关键组件,它们确保系统的高效和有序执行。本文将探讨这些概念,特别是线程管理、信号量、互斥锁、消息队列和邮箱处理。
- 任务管理:RTX提供任务创建、调度和优先级管理,确保任务按照优先级及时执行。
- 同步与通信:包括信号量、互斥锁、消息队列和邮箱,促进任务间的同步和数据交换。
- 内存管理:内存池和动态内存分配,有效管理有限的系统资源。
- 定时器服务:虚拟和硬件定时器,支持周期性任务和一次性事件触发。
- 中断处理:保证中断服务的快速响应,同时保持任务的上下文安全。
- 线程安全:通过内核级保护机制,防止多线程环境下的数据竞争和死锁。
3 同步与通信
在实时操作系统(RTOS)中,同步与通信是确保任务间协调执行和数据交换的关键机制。以下是关于实时操作系统中同步与通信的几个核心概念和方法:
3.1 同步(Synchronization)
-
目的:确保多个任务或中断处理程序在访问共享资源时的有序性和一致性,防止数据竞争和不一致。
-
方法:
- 互斥锁(Mutex):用于保护临界区,确保同一时间只有一个任务可以访问共享资源。
- 信号量(Semaphore):不仅可以实现互斥访问,还可以用于计数资源的可用性,支持多任务等待同一资源。
- 事件标志(Event Flags):用于任务间的简单状态通信,一个任务可以设置某些事件标志,另一个任务可以等待这些标志被设置。
- 消息队列(Message Queue):允许任务间传递数据结构或消息,同时也可以用作同步机制,发送者和接收者通过队列进行异步通信。
3.2 设计原则
- 最小化阻塞:选择适当的同步和通信机制,减少任务等待时间,提高系统响应速度。
- 确定性:确保所有同步和通信操作的时间复杂度是可预测的,以满足实时性要求。
- 资源效率:考虑内存和CPU开销,选择最适合应用需求的机制。
- 错误处理:实现健壮的错误处理逻辑,比如超时处理、死锁预防等。
3.3 实例应用
在多传感器数据融合的场景中,可以使用消息队列来收集来自不同传感器的任务数据,并在主控制任务中进行融合处理。
在电机控制应用中,通过互斥锁保护对电机控制寄存器的访问,避免并发写入导致的控制混乱。
综上所述,实时操作系统中的同步与通信机制是实现可靠、高效、实时性应用的基础,正确地设计和应用这些机制对于保证系统性能和稳定性至关重要。
4 信号量
我们接下来将详细介绍信号量和互斥锁。信号量是一种同步机制,用于控制对共享资源的访问。它可以是计数信号量或二进制信号量,用于管理多个线程的并发访问。
4.1 定义信号量
信号量是一个计数器,用于控制对公共资源的访问。计数信号量可以有多个资源,二进制信号量只有两个状态:空闲(1)和占用(0)。
一般在文件开头会看到这样的定义:osSemaphoreDef
。
4.1.1 代码
// 定义一个名为app_rtx_test_semaphore的互斥量
osSemaphoreDef(app_rtx_test_semaphore);
// 定义一个变量app_rtx_test_semaphore_id,用于存储互斥量的ID
// 在实际操作中,这个ID将用于在运行时访问和操作互斥量
osSemaphoreId app_rtx_test_semaphore_id = NULL;
/**
* 定义一个OS semaphore的结构体实例。
* 这是一个宏,用于静态定义一个互斥量( semaphore),以便在操作系统中使用。
*
* @param name 互斥量的名称,用于标识和访问该互斥量。
*/
#define osSemaphoreDef(name) \
static StaticSemaphore_t os_semaphore_cb_##name; /* 在静态内存中定义一个静态互斥量变量 */ \
const osSemaphoreDef_t os_semaphore_def_##name = \
{ NULL, 0U, (&os_semaphore_cb_##name), sizeof(StaticSemaphore_t) } /* 定义互斥量结构体,包含互斥量的控制块地址和其他必要信息 */
4.1.2 参数/函数讲解
序号 | 函数 | 说明 |
---|---|---|
1 | osSemaphoreId | 定义变量来存储信号量的 ID |
2 | osSemaphoreDef | 定义信号量结构体 |
4.2 创建信号量
创建信号量通常通过调用 osSemaphoreCreate()
函数实现,传入定义好的信号量结构体和初始值。
4.2.1 代码
/**
* 初始化名为app_rtx_test_semaphore的信号量。
* 如果互斥量尚未创建,此函数将创建它并将其ID存储在全局变量app_rtx_test_semaphore_id中。
*
* @return 总是返回0,表示初始化成功。
*/
int app_rtx_test_sem_init(void)
{
// 检查互斥量ID是否为空
if (app_rtx_test_semaphore_id == NULL) {
// 创建互斥量,传入之前定义的信号量结构体和初始信号量值(这里是1)
app_rtx_test_semaphore_id = osSemaphoreCreate(osSemaphore(app_rtx_test_semaphore), 1);
}
// 初始化成功,返回0
return 0;
}
4.2.2 参数/函数讲解
序号 | 函数 | 说明 |
---|---|---|
1 | osSemaphoreCreate | 创建信号量 |
2 | osSemaphore | 获取前面定义的信号量结构体 |
4.3 获取信号量
线程通过 osSemaphoreWait()
函数请求信号量,如果资源可用,函数会立即返回;否则,线程会被挂起,直到资源可用。
4.3.1 代码
/**
* 请求获取app_rtx_test_semaphore互斥量的锁。
* 此函数会阻塞直到获得锁,或者在等待过程中被信号中断。
*
* @return 总是返回0,表示锁获取成功。
*/
int app_rtx_test_sem_lock(void)
{
// 等待获取互斥量锁,如果资源不可用,将一直等待
osSemaphoreWait(app_rtx_test_semaphore_id, osWaitForever);
// 锁获取成功,返回0
return 0;
}
4.3.2 参数/函数讲解
序号 | 函数 | 说明 |
---|---|---|
1 | osSemaphoreWait | 等待获取信号量 |
4.4 释放信号量
当线程完成对资源的操作后,通过 osSemaphoreRelease()
函数释放信号量,让其他等待的线程有机会获取。
4.4.1 代码
/**
* 释放app_rtx_test_semaphore互斥量的锁。
* 此函数允许其他任务获取该互斥量。
*
* @return 总是返回0,表示锁释放成功。
*/
int app_rtx_test_sem_unlock(void)
{
// 释放信号量锁,允许其他任务使用
osSemaphoreRelease(app_rtx_test_semaphore_id);
// 锁释放成功,返回0
return 0;
}
4.4.2 参数/函数讲解
序号 | 函数 | 说明 |
---|---|---|
1 | osSemaphoreRelease | 释放信号量,允许其他任务使用 |
5 互斥锁
互斥锁是另一种同步机制,确保同一时间只有一个线程访问特定资源。
5.1 定义
一般在文件开头会看到这样的定义:osMutexDef
。
5.1.1 代码
// 声明一个互斥锁实例,使用osMutexDef宏并传入名称app_rtx_test_mutex
osMutexDef(app_rtx_test_mutex);
// 定义一个osMutexId类型的变量,用于存储互斥锁的ID
// 在初始化后,该变量将持有app_rtx_test_mutex的标识符,以便在需要时进行锁定和解锁操作
osMutexId app_rtx_test_mutex_id = NULL;
/**
* 定义一个互斥锁的宏。
*
* 该宏用于静态定义一个互斥锁(Mutex),支持递归和优先级继承特性。它通过提供一个名称来创建
* 该互斥锁的相关静态数据结构。
*
* @param name 互斥锁的名称。该名称将用于为互斥锁的控制块和定义结构体命名。
*/
#define osMutexDef(name) \
static StaticSemaphore_t os_mutex_cb_##name; /* 控制块静态存储区 */ \
const osMutexDef_t os_mutex_def_##name = \
{ NULL, osMutexRecursive | osMutexPrioInherit, (&os_mutex_cb_##name), sizeof(StaticSemaphore_t) } /* Mutex定义结构体 */
5.1.2 参数/函数讲解
序号 | 函数 | 说明 |
---|---|---|
1 | osMutexId | 定义用于存储互斥锁的ID |
2 | osMutexDef | 定义互斥锁结构体 |
5.2 创建
创建互斥锁通常使用 osMutexCreate()
函数,传入互斥锁的定义。
5.2.1 代码
/**
* 初始化指定的互斥锁。
*
* 此函数负责初始化之前通过osMutexDef定义的app_rtx_test_mutex互斥锁。
* 如果该互斥锁尚未被创建(即其ID为NULL),则会调用osMutexCreate进行创建。
*
* @return 返回0表示初始化成功。由于此实现未处理失败情况,故假设初始化总是成功的。
*/
int app_rtx_test_mutex_init(void)
{
// 检查互斥锁是否已初始化
if (app_rtx_test_mutex_id == NULL) {
// 使用osMutexDef定义的结构体创建互斥锁,并将其ID保存到app_rtx_test_mutex_id中
app_rtx_test_mutex_id = osMutexCreate((osMutex(app_rtx_test_mutex)));
}
// 初始化成功,返回0
return 0;
}
5.2.2 参数/函数讲解
序号 | 函数 | 说明 |
---|---|---|
1 | osMutexCreate | 创建互斥锁 |
2 | osMutex | 获取前面定义的互斥锁结构体 |
5.3 加锁
线程使用 osMutexLock()
函数请求互斥锁,如果锁未被占用,线程会立即加锁;否则,线程会被挂起等待。
5.3.1 代码
/**
* @brief 尝试获取互斥锁
*
* @description 该函数用于请求一个名为`app_rtx_test_mutex_id`的互斥锁。
* 使用`osWaitForever`参数表示函数将一直等待直到获得锁。
*
* @param[in] 无
*
* @return 返回值0表示成功获取了互斥锁。
*
* @note 若在多线程环境下其他线程已持有该锁,则调用此函数的线程会被挂起,
* 直到锁被释放。这可能导致当前线程阻塞,因此使用`osWaitForever`需谨慎。
*/
int app_rtx_test_mutex_lock(void)
{
// 调用osMutexWait来请求互斥锁,如果无法立即获取则无限等待
osMutexWait(app_rtx_test_mutex_id, osWaitForever);
// 成功获取锁后返回0
return 0;
}
5.3.2 参数/函数讲解
序号 | 函数 | 说明 |
---|---|---|
1 | osMutexWait | 等待获取互斥锁 |
这个函数 app_rtx_test_mutex_lock
用于获取一个已知的互斥锁 app_rtx_test_mutex
。它调用了实时操作系统(RTOS)的API osMutexWait
,传入互斥锁的句柄和一个标志 osWaitForever
,表示如果锁不可用,当前任务将被挂起,直到能够获取锁为止。如果成功获取了锁,函数返回0。
5.4 解锁
线程完成操作后,使用 osMutexUnlock()
函数释放互斥锁,允许其他线程获取。
5.4.1 代码
/**
* 释放app_rtx_test_mutex互斥锁。
*
* 当前任务持有互斥锁时,此函数将释放它,允许其他等待该锁的任务继续执行。
*
* @return 返回0表示成功释放锁。由于此实现未处理失败情况,故假设锁总是能被成功释放。
*/
int app_rtx_test_mutex_unlock(void)
{
// 调用RTX API释放互斥锁
osMutexRelease(app_rtx_test_mutex_id);
// 释放锁成功,返回0
return 0;
}
5.4.2 参数/函数讲解
序号 | 函数 | 说明 |
---|---|---|
1 | osMutexRelease | 释放互斥锁,允许其他任务使用 |
总结
感谢观看,这里就是 boot loader 引导程序的讲解,如果觉得有帮助,请给文章点个赞吧,让更多的人看到。🌹 🌹 🌹
也欢迎你,关注我。👍 👍 👍
原创不易,还希望各位大佬支持一下,你们的点赞、收藏和留言对我真的很重要!!!💕 💕 💕 最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!下期再见。🎉
更多专栏订阅:
😀 【LeetCode题解(持续更新中)】
🥇 【恒玄BES】
🌼 【鸿蒙系统】
💎 【蓝牙协议栈】
🎃 【死机分析】
👑 【Python脚本笔记】
🚝 【Java Web项目构建过程】
💛 【微信小程序开发教程】
⚽ 【JavaScript随手笔记】
🤩 【大数据学习笔记(华为云)】
🦄 【程序错误解决方法(建议收藏)】
🔐 【Git 学习笔记】
🚀 【软件安装教程】
订阅更多,你们将会看到更多的优质内容!!