鸿蒙Hi3861学习七-Huawei LiteOS-M(信号量)

一、简介

        信号量(Semaphore)是一种实现任务间通信的机制,实现任务之间同步临界资源的互斥访问。常用于协助一组相互竞争的任务来访问临界资源。

        在多任务系统中,各任务之间需要同步或互斥实现临界资源的保护,信号量功能可以为用户提供这方面的支持。

        通常一个信号量的计数值用于对应有效的资源数,表示剩下的可被占用的互斥资源数。其值的含义分为两种情况:

  • 0,表示没有积累下来的Post信号量操作,且有可能有再此信号量上阻塞的任务
  • 正值,表示有一个或多个Post信号量操作。

        以同步为目的的信号量和以互斥为目的的信号量在使用上是有不同的:

  • 同步信号量:信号量在创建后被置为空,任务1取信号量而阻塞,任务2在某种条件发生后,释放信号量,于是任务1得以进入READY或RUNNING态,从而达到两个任务间的同步。
  • 互斥信号量:信号量创建后计数是满的,在需要使用临界资源时,先取信号量,使其变空。这样,其他任务需要使用临界资源时就会因为无法取得信号量而阻塞,从而保证了临界资源的安全。

        更多信号量概念,可参考:FreeRTOS学习五(信号量)_freertos信号量用法_t_guest的博客-CSDN博客

Semaphores

二、运行机制

        信号量初始化为配置的N个信号量申请内存(N值可以由用户自行配置,受内存限制),并把所有的信号量初始化成未使用状态,并加入到未使用链表中供系统使用

        信号量创建,从未使用的信号量链表中获取一个信号量,并设定初值

        信号量申请,若其计数值大于0,则直接减1并返回成功否则任务阻塞,等待其他任务释放该信号量,等待的超时时间可设定。当任务被一个信号量阻塞时,将该任务挂到信号量等待任务队列的队尾

        信号量释放,若没有任务等待该信号量,则直接将计数器加1返回。否则唤醒该信号量等待任务队列上的第一个任务。

        信号量删除,将正在使用的信号量置为未使用的状态,并挂回到未使用链表中。

        信号量允许多个任务在同一时刻访问同一资源,但会限制同一时刻访问此资源的最大任务数目。访问同一资源的任务数达到该资源的最大数量时,会阻塞其他试图获取该资源的任务,直到有任务释放该信号量。

三、API介绍

      osSemaphoreNew

        函数功能:

        创建信号量。不可在中断服务中使用

        函数原型:

osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr)

        参数:

        max_count:信号量最大的可用数量

        initial_count:初始化时可用数量

        attr:相关属性,只有在自定义内存才用的到。默认为NULL

        返回值:

        NULL:失败

        其他值:信号量标识符

        实例:

osSemaphoreId_t sem1;
sem1 = osSemaphoreNew(4, 0, NULL);

      osSemaphoreAcquire

        函数功能:

        阻塞任务,等待信号量。如果等待时间为0,可以在中断中调用

        函数原型:

osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout)

        参数:

        semaphore_id:信号量ID。由osSemaphoreNew信号量创建时获得。

        timeout:等待超时时间。osWaitForever死等

        返回值:

        osOK:等到信号量

        其他值:异常

typedef enum {
  /** Operation completed successfully */
  osOK                      =  0,
  /** Unspecified error */
  osError                   = -1,
  /** Timeout */
  osErrorTimeout            = -2,
  /** Resource error */
  osErrorResource           = -3,
  /** Incorrect parameter */
  osErrorParameter          = -4,
  /** Insufficient memory */
  osErrorNoMemory           = -5,
  /** Service interruption */
  osErrorISR                = -6,
  /** Reserved. It is used to prevent the compiler from optimizing enumerations. */
  osStatusReserved          = 0x7FFFFFFF
} osStatus_t;

        实例:

osSemaphoreId_t sem1;
osStatus_t ret = osSemaphoreAcquire(sem1,osWaitForever);

      osSemaphoreRelease

        函数功能:

        释放信号量。可以在中断中调用

        函数原型:

osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id)

        参数:

        semaphore_id:信号量ID。由osSemaphoreNew信号量创建时获得。

        返回值:

        osOK:成功

        其他值:异常

        实例:

osSemaphoreId_t sem1;
osStatus_t ret = osSemaphoreRelease(sem1);

      osSemaphoreGetCount

        函数功能:

        获取当前可用的信号量数目。可以在中断中被调用

        函数原型:

uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id)

        参数:

        semaphore_id:信号量ID。由osSemaphoreNew信号量创建时获得。

        返回值:

        可用的信号量数

        实例:

osSemaphoreId_t sem1;
osSemaphoreGetCount(sem1)

      osSemaphoreDelete

        函数功能:

        删除信号量。不可在中断中被调用。

        函数原型:

osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id)

        参数:

        semaphore_id:信号量ID。由osSemaphoreNew信号量创建时获得。

        返回值:

        osOK:成功

        其他值:异常

        实例:

osSemaphoreId_t sem1;
osStatus_t ret = osSemaphoreDelete(sem1);

四、实例

        创建一个经典的生产者与消费者模型。其中,生产者一次生产3个,消费之每次消费一个。但是生产者每5秒生产一次。消费者有可消耗就消耗。

#define LOG_I(fmt, args...)   printf("<%8ld> - [TIMER]:"fmt"\r\n",osKernelGetTickCount(),##args);
#define LOG_E(fmt, args...)   printf("<%8ld>-[TIMER_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);

osSemaphoreId_t sem1;

osThreadId_t g_thread1_id = NULL;
osThreadId_t g_thread2_id = NULL;

/*****任务一*****/
void thread1(void)
{
    LOG_I("thread 1 start");

    while (1)
    {
        LOG_I("thread 1 delay 5S");
        osDelay(500);
        LOG_I("thread 1 release semaphore before");
        osSemaphoreRelease(sem1);
        osSemaphoreRelease(sem1);
        osSemaphoreRelease(sem1);
        LOG_I("thread 1 release semaphore after,viable sema count:%d",osSemaphoreGetCount(sem1));
    }

    LOG_I("thread 1 break");
    
    osThreadTerminate(g_thread1_id);
}

/*****任务二*****/
void thread2(void)
{
    LOG_I("thread 2 start");
    
    while (1)
    {
        LOG_I("thread2 acquire semaphore wait,sema count:%d",osSemaphoreGetCount(sem1));
        osSemaphoreAcquire(sem1,osWaitForever);
        LOG_I("thread2 acquire semaphore accepted");
    }
    LOG_I("thread 2 end");
}

void Hello_World(void)
{  

    LOG_I("Test semaphore");

    sem1 = osSemaphoreNew(4, 0, NULL);
    if (sem1 == NULL)
    {
        LOG_E("Falied to create Semaphore1!");
    }
    osThreadAttr_t attr;

    attr.name = "thread1";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 2;
    attr.priority = osPriorityNormal; 

    g_thread1_id  = osThreadNew((osThreadFunc_t)thread1, NULL, &attr);
    if (g_thread1_id == NULL)
    {
        LOG_E("Falied to create thread1!");
    }

    attr.name = "thread2";
    attr.stack_size = 1024 * 2;

    g_thread2_id = osThreadNew((osThreadFunc_t)thread2, NULL, &attr);
    if (g_thread2_id == NULL)
    {
        LOG_E("Falied to create thread2!");
    }
}

        看结果:

         可以看到,在任务1里直接释放三个信号量,而此时调用osSemaphoreGetCount只能获取到2个可用。是因为在osSemaphoreRelease释放信号量时,因为任务2已经在等待信号量,所以任务1释放的一个信号量马上被任务2所获取。

        那为什么任务2获取到信号量后并没有马上到任务2执行呢?是因为两个任务的优先级是一样的只有等到任务1释放了系统后,任务2才能开始运行。如果我们把任务2的优先级设置比任务1高结果会如何呢?

        在代码中添加一行代码:

         再看一下运行结果。

         这里可以看到,因为任务2的优先级比任务1的优先级高。所以,当任务1释放信号量后,任务2马上抢占了系统的使用权。任务1因为优先级低,被挂起。当任务2执行完后,任务1才能继续执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/18756.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面对AI“龙卷风”破坏力 白宫“软着陆”欧盟“硬防御”

ChatGPT的风靡与风险将OpenAI的CEO山姆奥特曼&#xff08;Sam Altman&#xff09;送进白宫&#xff0c;他被蹲守在美国总统府邸的记者们围追&#xff0c;面对5月4日白宫发起的AI风险治理会议&#xff0c;奥特曼很官方地给出“重要也很及时”的回应&#xff0c;自信的反复强调“…

chatGPT润色中英论文软件-文章修改润色器

chatGPT可以润色英文论文吗&#xff1f; ChatGPT可以润色英文论文&#xff0c;它具备自动纠错、自动完善语法和严格全面的语法、句法和内容结构检查等功能&#xff0c;可以对英文论文进行高质量的润色和优化。此外&#xff0c;ChatGPT还支持学术翻译润色、查重及语言改写等服务…

Java入门指南:从零开始的基础语法

java语言概述 Java是一种高级编程语言&#xff0c;最初由Sun Microsystems&#xff08;现在是Oracle Corporation的一部分&#xff09;在1995年推出。Java以其简单、可移植和安全的特性而闻名&#xff0c;并广泛用于各种应用程序开发&#xff0c;从桌面应用程序到移动应用程序和…

icevision环境安装

Installation - IceVision # 1. git clone 代码# pip 换源&#xff1a; ~/.pip/pip.conf 隐藏文件[global] index-url https://pypi.tuna.tsinghua.edu.cn/simple [install] trusted-hostmirrors.aliyun.compip install -e .[all,dev]ImportError: cannot import name Multi…

ASEMI代理ADUM131E1BRWZ-RL原装ADI车规级ADUM131E1BRWZ-RL

编辑&#xff1a;ll ASEMI代理ADUM131E1BRWZ-RL原装ADI车规级ADUM131E1BRWZ-RL 型号&#xff1a;ADUM131E1BRWZ-RL 品牌&#xff1a;ADI /亚德诺 封装&#xff1a;SOIC-16-300mil 批号&#xff1a;2023 安装类型&#xff1a;表面贴装型 引脚数量&#xff1a;16 工作温度…

WPF异常处理详解

总目录 文章目录 总目录一、WPF异常1 未捕获异常2 模拟未捕获异常场景 二、处理未捕获异常1 DispatcherUnhandledException 异常捕获2 UnhandledException异常捕获3 UnobservedTaskException异常捕获4 异常捕获的综合使用 结语 一、WPF异常 1 未捕获异常 正常情况下&#xff…

又一里程碑,alibaba首推Java技术成长笔记,业内评级“钻石级”

前言 根据数据表明&#xff0c;阿里巴巴已经连续3年获评最受欢迎的中国互联网公司&#xff0c;实际上阿里巴巴无论在科技创新力还是社会创造价值这几个方面&#xff0c;都是具有一定代表里的。在行业内&#xff0c;很多互联网企业也将阿里作为自己的标杆&#xff0c;越来越多的…

【PSO-LSTM】基于PSO优化LSTM网络的电力负荷预测(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

iOS与Android应用开发的对比:如何选择最佳开发平台?

第一章&#xff1a;引言 在移动应用开发领域&#xff0c;iOS和Android是最为流行的操作系统。选择最佳的开发平台可以使开发人员更有效地开发和发布应用程序。本文将分析iOS和Android应用开发的优缺点&#xff0c;并提供一些有关如何选择最佳开发平台的建议。 第二章&#xf…

Kali-linux攻击WordPress和其他应用程序

今天越来越多的企业利用SAAS&#xff08;Software as a Service&#xff09;工具应用在他们的业务中。例如&#xff0c;他们经常使用WordPress作为他们网站的内容管理系统&#xff0c;或者在局域网中使用Drupal框架。从这些应用程序中找到漏洞&#xff0c;是非常有价值的。 为…

《算经》中的百钱买百鸡问题,你会做吗?试下看看(39)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 欢迎和猫妹一起&#xff0c;趣味学Python。 今日主题 你知道我国历史上有个王朝叫北魏吗&#xff1f; 北魏&#xff08;386年—534年&#xff09;&#xff0c;南北朝时期北…

AdaSparse: 自适应稀疏网络的多场景CTR预估建模

▐ 摘要 CTR(Click-through rate)预估一直是推荐/广告领域重要技术之一。近年来&#xff0c;通过统一模型来服务多个场景的预估建模已被证明是一种有效的手段。当前多场景预估技术面临的挑战主要来自两方面&#xff1a;1&#xff09;跨场景泛化能力&#xff1a;尤其对稀疏场景&…

vscode IDE 能用的上的扩展工具功能介绍

记录分享vscode扩展&#xff0c;包括提升开发效率。必备。主题美化。ChatGPT等。 参考 vscode-extensions [Best] 记录分享方式&#xff0c;整理自己用的扩展&#xff0c;还有一键备份和还原方法。 ⭐快速下载和使用扩展 后面会介绍很多vscode扩展.这裡有一个技巧&#xff0c;…

为什么二极管具有单向导通性

大家都知道二极管具有单向导通性&#xff0c;比如一个双极性的信号通过二极管后会变成一个单极性的信号。 为了弄清这个问题先来看一下二极管的构成。 在纯净的硅晶体中掺入五价元素&#xff0c;比如磷&#xff0c;就形成了N型半导体&#xff0c;掺入的五价元素多余的电子很容…

uboot移植Linux-SD驱动代码解析

一、uboot与linux驱动 1.1、uboot本身是裸机程序 (1)狭义的驱动概念是指&#xff1a;操作系统中用来具体操控硬件的代码叫驱动 广义的驱动概念是指&#xff1a;凡是操控硬件的代码都叫驱动 (2)裸机程序中是直接使用寄存器的物理地址来操控硬件的&#xff0c;操作系统中必须通…

实时聊天如何做,让客户眼前一亮(一)

网站上的实时聊天功能应该非常有用&#xff0c;因为它允许客户支持立即帮助用户。在线实时聊天可以快速轻松地访问客户服务部门&#xff0c;而它也代表着企业的门面。 让我们讨论一下如何利用SaleSmartly&#xff08;ss客服&#xff09;在网站中的实时聊天视图如何提供出色的实…

纯前端JS实现文件上传解析渲染页面

AI真的能代替前端吗&#xff1f; 回答&#xff1a;不会完全代替 能用吗&#xff1f;复制到项目中只会报错 爆红 ……他完全不能理解你需要什么JavaScript&#xff08;简称JS&#xff09;是一种轻量级的脚本语言&#xff0c;主要用于在Web页面上添加交互行为。它由三个不同的…

项目环境配置、不知晓问题自己搜索后得到的解答

目录 Anolis OS龙蜥操作系统 Kernel Selection 4.18.0(RHCK) Compatible with RHEL (kernel-4.18.0) 4.19.91(ANCK) Support Anolis OS verified platform (kernel-4.19.91) 这两个内核选择哪个比较好呢&#xff1f; 我的C盘有些满&#xff0c;我该如何删除一些我需要的东西…

家用洗地机哪个好用?家用洗地机分享

洗地机是一种代表现代化清洁的设备&#xff0c;它具有高效、环保、经济、智能等多种特点。洗地机可以为您提供先进的清洁技术和设备&#xff0c;为您的清洁工作提供有力的支持。洗地机可以适应不同场所和建筑物的需求&#xff0c;提高工作效率和卫生形象。因此&#xff0c;选择…

logstash介绍和使用-ELK文章2

官方 Logstash 是免费且开放的服务器端数据处理管道&#xff0c;能够从多个来源采集数据&#xff0c;转换数据&#xff0c;然后将数据发送到您最喜欢的“存储库”中。 下载和文档&#xff1a;https://www.elastic.co/cn/logstash/ docker部署&#xff1a;https://hub.docker.…