小米vela系统(基于开源nuttx内核)——如何使用信号量进行PV操作

server/2025/1/14 17:56:51/

如何使用信号量进行PV操作

前言

在嵌入式系统中,任务间的同步与通信是非常重要的。NuttX作为一款轻量级实时操作系统,提供了多种同步机制,其中信号量(Semaphore)是一种常见且高效的工具,用于实现线程或任务之间的同步。本文将深入探讨如何在NuttX中使用信号量,并通过一个实例来展示其应用。

在 Vela 操作系统(nuttx内核)中,使用标准的 POSIX接口,信号量的管理也是与linux系统类似的。
在这里插入图片描述

信号量

1. 信号量简介

信号量是一种用于线程间同步的机制,它可以控制多个任务的访问权限。常见的信号量类型有:

二值信号量(Binary Semaphore):信号量的值只有两个状态,0和1,常用于实现互斥锁。
计数信号量(Counting Semaphore):信号量的值可以为任意正整数,适用于控制某些资源的访问数量。
信号量通常由一个线程/任务进行“发布”(sem_post()),另一个线程/任务进行“等待”(sem_wait())。通过这种机制,任务可以在特定条件下进行同步,确保共享资源的安全访问。

在NuttX系统中,信号量的实现和使用与POSIX标准兼容,开发者可以使用标准的API来进行操作。

2. NuttX中信号量的创建与使用

NuttX提供了一些API来操作信号量,常见的函数包括:

这些API非常方便地用于线程同步,特别是在多线程环境下。

2.1 Nuttx信号量的初始化和销毁

这里申明了一个全局的下载标志信号量,初始化为0,表示当调用wait信号量的线程在程序开始时候就会被阻塞住回等待信号量来触发执行

sem_t g_download_sem;  // 声明信号量// 初始化信号量
sem_init(&g_download_sem, 0, 0);  // 初始值为0,表示线程会等待// 销毁信号量
sem_destroy(&g_download_sem);
  • sem_init(&g_download_sem, 0, 0):初始化一个信号量 g_download_sem,第二个参数为0表示信号量在进程间共享,第三个参数为0表示信号量的初始值为0。
  • sem_destroy(&g_download_sem):销毁信号量,释放资源。

2.2 信号量的等待和发布

// 等待信号量
sem_wait(&g_download_sem);// 发布信号量
sem_post(&g_download_sem);
  • sem_wait(&g_download_sem):如果信号量的值为0,调用该函数的线程会被阻塞,直到信号量被发布(sem_post())。
  • sem_post(&g_download_sem):发布信号量,将信号量的值加1。如果有线程在等待该信号量,它将被唤醒,继续执行。

3. 信号量的实际应用:下载任务示例

为了更好地理解信号量的使用,接下来通过一个示例来演示信号量如何用于任务间同步。该示例涉及两个线程,一个是常驻线程(download_thread),等待信号量来触发下载任务,另一个线程(signal_thread)负责发送信号量,触发下载。

3.1 实际代码

#include <nuttx/config.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>sem_t g_download_sem;  // 全局信号量// 下载任务函数
void download_task(void)
{printf("Downloading... \n");usleep(2000000);  // 模拟下载过程printf("Download completed!\n");
}// 常驻下载线程,等待信号量并执行下载任务
void *download_thread(void *arg)
{while (1){printf("Download thread waiting for signal...\n");// 等待信号量sem_wait(&g_download_sem);// 收到信号量后执行下载任务download_task();}return NULL;
}// 发送信号量的线程
void *signal_thread(void *arg)
{// 模拟在某个时间点或条件触发信号量sleep(1);  // 模拟等待1秒printf("Signal thread sending signal to download thread...\n");// 给信号量发送信号,触发下载任务sem_post(&g_download_sem);return NULL;
}int main(int argc, char *argv[])
{pthread_t download_tid, signal_tid;// 初始化信号量sem_init(&g_download_sem, 0, 0);  // 初始信号量为0,线程开始时会等待// 创建下载线程pthread_create(&download_tid, NULL, download_thread, NULL);// 创建发送信号量的线程pthread_create(&signal_tid, NULL, signal_thread, NULL);// 等待信号线程完成pthread_join(signal_tid, NULL);// 等待下载线程执行完毕pthread_join(download_tid, NULL);// 清理信号量sem_destroy(&g_download_sem);return 0;
}

3.2 代码说明

  • 常驻下载线程(download_thread
    • 该线程持续运行,并在每次调用 sem_wait(&g_download_sem) 时阻塞,直到接收到信号量信号量的接收标志着可以开始下载任务。
  • 信号量触发线程(signal_thread
    • 在模拟的条件下(例如延时1秒),该线程会调用 sem_post(&g_download_sem) 来触发下载线程开始执行下载任务。
  • 主线程(main
    • 主线程初始化信号量,创建并启动下载线程和信号量触发线程,最后等待它们的执行完成并清理资源。

3.3 执行说明

  • 程序启动后,main 线程创建两个线程:

    • download_thread 会等待信号量,并在收到信号量后执行下载任务。
    • signal_thread 在延时1秒后触发信号量,使得 download_thread 执行下载任务。
  • signal_thread 发送信号量后,download_thread 被唤醒并开始执行模拟的下载任务。

  • 最后,main 线程等待两个子线程执行完毕,并清理信号量资源。

4. 信号量的优势与应用场景

信号量作为一种同步机制,在多线程或多任务的系统中有广泛的应用。它的优势在于:

  • 简单性信号量的基本操作非常简单,可以轻松实现任务间的同步。
  • 高效性信号量的实现通常很轻量,适用于需要低延迟和高效同步的场景。
  • 灵活性:可以通过计数信号量控制资源的访问数量,通过二值信号量实现互斥。

5. 常见应用场景:

  1. 任务同步:当多个任务之间需要协调工作时,可以使用信号量来同步它们的执行。
  2. 资源管理:在有限资源的情况下,信号量可以用来限制并发任务的数量。例如,限制同时访问某个硬件资源的线程数。
  3. 事件通知:一个任务等待某个事件的发生,另一个任务在事件发生时发布信号量来通知等待任务。

总结

NuttX提供了POSIX兼容的信号量API,使得在多线程环境下进行任务同步变得更加简单和高效。通过本文中的示例,我们了解了如何在NuttX中创建和使用信号量,并展示了如何利用信号量控制任务的执行。信号量在嵌入式系统中应用广泛,特别是在需要多任务协作和资源管理的场景中,信号量提供了一种简洁的解决方案。


http://www.ppmy.cn/server/158344.html

相关文章

PyTorch 张量的分块处理介绍

分块处理是将大型张量分解成较小的块&#xff0c;以便更高效地进行计算&#xff0c;减少内存占用&#xff0c;特别适用于处理超大张量的场景&#xff08;如深度学习中的大批量数据或大型模型训练&#xff09;。 PyTorch 提供了多种方法来分块张量&#xff0c;包括 chunk、spli…

c++ haru生成pdf输出文本实例

haru是一个开源的生成pdf的库&#xff0c;花时间终于编译成功&#xff0c;以下是一个特别简单的写文本的实例&#xff1a; #include "hpdf.h" void CDemoDlg::OnBnClickedOk() { HPDF_Error_Handler error_handler NULL; HPDF_Doc pdf; pdf HPDF_New(…

docker run一个镜像如何指定最大可使用的内存大小、cpu大小

在 Docker 中&#xff0c;你可以通过 --memory 和 --cpus 参数来指定容器的最大内存和 CPU 限制。这样可以确保容器不会超出特定的资源限制&#xff0c;从而避免影响主机的其他进程。 1. 限制内存&#xff08;--memory&#xff09; 通过 --memory 或 -m 参数&#xff0c;你可…

Moq与xUnit在C#单元测试中的应用

一、引言&#xff1a;开启单元测试的魔法之旅 嘿&#xff0c;亲爱的编程小伙伴们&#xff01;&#x1f44b; 在软件开发的奇妙世界里&#xff0c;有一项神奇的技术&#xff0c;能为我们的代码保驾护航&#xff0c;让开发过程如虎添翼&#xff0c;那便是单元测试。它宛如给代码…

浅谈云计算07 | 云安全机制

浅谈云计算安全机制&#xff1a;全方位守护云端世界 一、引言二、加密技术&#xff1a;数据的隐形护盾三、散列机制&#xff1a;数据完整性的忠诚卫士四、数字签名&#xff1a;数据来源与真伪的鉴定专家五、公钥基础设施&#xff08;PKI&#xff09;&#xff1a;信任的基石六、…

WordEmbeddingPositionEmbedding

文章目录 1. Word Embedding2. Position Embedding3. python 代码 1. Word Embedding 根据矩阵序列实现在nn.Embedding中抽取制定的行作为词向量&#xff0c;长度不同时&#xff0c;自动填充到统一长度 2. Position Embedding 3. python 代码 import torch import torch.nn …

51单片机入门基础

目录 一、基础知识储备 &#xff08;一&#xff09;了解51单片机的基本概念 &#xff08;二&#xff09;掌握数字电路基础 &#xff08;三&#xff09;学习C语言编程基础 二、开发环境搭建 &#xff08;一&#xff09;硬件准备 &#xff08;二&#xff09;软件准备 三、…

Python----Python基础(字符串,列表,元组,字典,集合的总结)

一、字符串 str&#xff0c;基本用法&#xff1a;拼接&#xff0c;复制&#xff0c;长度&#xff0c;索引&#xff0c;切片&#xff0c;查找&#xff0c;替换&#xff0c;大小写转化&#xff0c;去除空格&#xff0c;填充&#xff0c;分割&#xff0c;判断&#xff0c;可变字符…