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

ops/2025/1/15 17:18:24/

如何使用信号量进行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/ops/150034.html

相关文章

springMVC---resultful风格

目录 一、创建项目 pom.xml 二、配置文件 1.web.xml 2.spring-mvc.xml 三、图解 四、controller 一、创建项目 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi…

面试题(一天五道)

文章目录 面试题&#xff08;一天五道&#xff09;第一天1.redis五种类型2.redis持久化方式有哪些3.缓存雪崩是什么&#xff0c;如何解决4 缓存击穿是什么&#xff0c;如何解决5 缓存穿透是什么&#xff0c;如何解决 第二天1.redis中的hash类型如何进行存储1. 使用 HSET 命令设…

Clojure语言的学习路线

Clojure语言的学习路线 Clojure是一门现代的函数式编程语言&#xff0c;它运行在Java虚拟机&#xff08;JVM&#xff09;上&#xff0c;能够与 Java 生态系统无缝集成&#xff0c;使得 Clojure 拥有强大的库支持和良好的性能。此外&#xff0c;Clojure还拥有immutable 数据结构…

windows安装docker

安装 首先确保windows启用Hyper-V&#xff0c;子linux系统和虚拟机平台&#xff0c;且cpu开启虚拟化 重启等待应用生效 安装doxker desktop 下载链接 打开cmd&#xff0c;输入docker version查看安装情况 在服务类型查看docker服务是否启动&#xff0c;不是进入服务修改为自…

[人工智能自学] Python包学习-numpy

由于我并非该专业&#xff0c;我在学习之前google了几个比较靠前的人工智能学习路径&#xff1a; https://github.com/tangyudi/Ai-Learn https://github.com/apachecn/ai-roadmap/blob/master/ai-union-201904/README.md https://marlous.github.io/2019/01/18/%E4%BA%BA%E5%B…

Spring Cloud Alibaba - Nacos理论面试总结-未完结

临时实例和永久实例 临时实例和永久实例在 Nacos 中是一个非常非常重要的概念 之所以说它重要&#xff0c;主要是因为我在读源码的时候发现&#xff0c;临时实例和永久实例在底层的许多实现机制是完全不同的 临时实例 临时实例在注册到注册中心之后仅仅只保存在服务端内部一…

vue3项目大屏适配方案(scale)及vue-tv-focusable库使用

一. 适配方案代码(scale) 公共代码 export const useAdjustScale () > {// * 指向最外层容器const pageRef ref();// * 默认缩放值const scale {width: 1,height: 1,};// * 需保持的比例&#xff08;默认1.77778&#xff09; const designWidth 1920 const designHeig…

4Hive计算引擎

4Hive计算引擎 1 MR计算引擎2 Tez计算引擎3 Spark计算引擎 目前Hive支持MapReduce、Tez和Spark 三种计算引擎。 1 MR计算引擎 MR运行的完整过程&#xff1a; Map在读取数据时&#xff0c;先将数据拆分成若干数据&#xff0c;并读取到Map方法中被处理。数据在输出的时候&#…