信号量本质 信号量实验(控制车辆运行,优先级反转)互斥量

信号量本质

 前面介绍的队列(queue)可以用于传输数据:在任务之间、任务和中断之间。

消息队列用于传输多个数据,但是有时候我们只需要传递状态,这个状态值需要用一个
数值表示,比如:
卖家:做好了 1 个包子!做好了 2 个包子!做好了 3 个包子!
买家:买了 1 个包子,包子数量减 1
这个停车位我占了,停车位减 1
我开车走了,停车位加 1
在这种情况下我们只需要维护一个数值,使用信号量效率更高、更节省内存

信号量的特性

信号量的常规操作

信号量这个名字很恰当:
信号:起通知作用
量:还可以用来表示资源的数量
" " 没有限制时,它就是 " 计数型信号量 "(Counting Semaphores)
" " 只有 0 1 两个取值时,它就是 " 二进制信号量 "(Binary Semaphores)
支持的动作: "give" 给出资源,计数值加 1 "take" 获得资源,计数值减 1
计数型信号量的典型场景是:
计数:事件产生时 "give" 信号量,让计数值加 1 ;处理事件时要先 "take" 信号
量,就是获得信号量,让计数值减 1
资源管理:要想访问资源需要先 "take" 信号量,让计数值减 1 ;用完资源后
"give" 信号量,让计数值加 1
信号量的"give"、"take"双方并不需要相同,可以用于生产者-消费者场合:
生产者为任务 A B ,消费者为任务 C D
153
一开始信号量的计数值为 0 ,如果任务 C D 想获得信号量,会有两种结
果:
阻塞:买不到东西咱就等等吧,可以定个闹钟 ( 超时时间 )
即刻返回失败:不等
任务 A B 可以生产资源,就是让信号量的计数值增加 1 ,并且把等待这个
资源的顾客唤醒
唤醒谁?谁优先级高就唤醒谁,如果大家优先级一样就唤醒等待时间最长的

信号量跟队列的对比

两种信号量的对比 

信号量的计数值都有限制:限定了最大值。如果最大值被限定为 1,那么它就是二进制
信号量;如果最大值不是 1,它就是计数型信号量。

信号量函数

使用信号量时,先创建、然后去添加资源、获得资源。使用句柄来表示一个信号量。

创建

二进制信号量

xSemaphoreCreateBinary() 是 FreeRTOS 中用于创建二进制信号量的函数。二进制信号量是一个非常有用的同步机制,适用于任务之间的协调与互斥访问。

函数原型
SemaphoreHandle_t xSemaphoreCreateBinary(void);
返回值
  • 成功:返回一个有效的信号量句柄 (SemaphoreHandle_t)。
  • 失败:返回 NULL,这通常表示系统内存不足或信号量创建失败。
使用场景
  • 任务同步:一个任务可以在完成某个操作后,释放信号量,通知其他任务可以继续执行。
  • 互斥访问:确保同一时刻只有一个任务可以访问共享资源,以防数据竞争和不一致性。
计数型信号量

xSemaphoreCreateCounting() 是 FreeRTOS 中用于创建计数信号量的函数。计数信号量可以用于限制对共享资源的访问,支持多个任务同时访问,并且能够管理多个资源的可用数量。

函数原型
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);
参数
  • uxMaxCount:信号量的最大计数值,表示可以同时获得的最大资源数量。
  • uxInitialCount:信号量的初始计数值,表示在创建时可用的资源数量。
返回值
  • 成功:返回一个有效的信号量句柄 (SemaphoreHandle_t)。
  • 失败:返回 NULL,通常由于内存不足或系统限制。
使用场景
  • 资源池管理:当你有一个固定数量的资源(如线程池、连接池等)时,可以使用计数信号量来管理它们的分配和释放。
  • 任务同步:在多个任务间同步执行,允许一定数量的任务并行访问某些资源。

删除

对于动态创建的信号量,不再需要它们时,可以删除它们以回收内存。
vSemaphoreDelete 可以用来删除二进制信号量、计数型信号量,函数原型如下
函数原型
void vSemaphoreDelete(SemaphoreHandle_t xSemaphore);
参数
  • xSemaphore:要删除的信号量的句柄,类型为 SemaphoreHandle_t
注意事项
  1. 信号量状态:在调用 vSemaphoreDelete() 之前,确保没有任务正在使用该信号量。否则,可能会导致未定义的行为。

  2. 内存管理:使用 vSemaphoreDelete() 后,信号量的句柄将变为无效。后续尝试使用这个句柄(如调用 xSemaphoreTake()xSemaphoreGive())将会引发错误。

  3. 任务优先级:如果信号量被用在多个任务中,确保在所有任务完成其对信号量的使用后再进行删除。

give/take

give

xSemaphoreGive() 是 FreeRTOS 中用于释放信号量的函数。它的主要功能是将信号量的计数值增加,允许其他任务获取信号量。

函数原型
BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);
参数
  • xSemaphore:要释放的信号量的句柄,类型为 SemaphoreHandle_t
返回值
  • pdTRUE:成功释放信号量。
  • pdFALSE:释放信号量失败(通常在信号量未被占用时调用时会失败)。
使用场景
  • 任务同步:在多任务环境中,当一个任务完成了对某个共享资源的使用后,可以调用 xSemaphoreGive() 释放信号量,允许其他任务访问该资源。
  • 计数信号量:在计数信号量中,调用 xSemaphoreGive() 将信号量的计数增加,可以表示资源的可用数量。
take

xSemaphoreTake() 是 FreeRTOS 中用于获取信号量的函数。它的主要作用是尝试获得一个信号量,如果信号量可用,函数将成功返回,并将信号量的计数减一;如果信号量不可用,函数将根据设置的等待时间进行阻塞或立即返回失败。

函数原型
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
参数
  • xSemaphore:要获取的信号量的句柄,类型为 SemaphoreHandle_t
  • xTicksToWait:等待信号量可用的时间,以滴答数为单位。如果设置为 portMAX_DELAY,则任务将无限期阻塞,直到获得信号量。
返回值
  • pdTRUE:成功获取信号量。
  • pdFALSE:获取信号量失败(在设定的时间内没有获得信号量)。
使用场景
  • 任务同步:在多任务系统中,一个任务可能需要在访问共享资源之前先获取信号量,确保其他任务不会同时访问该资源。
  • 保护共享资源:通过信号量的机制,可以防止数据竞争和资源冲突。

信号量实验

控制车辆运行

static void CarTask(void *params)
{struct car *pcar = params;struct ir_data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 显示汽车 */ShowCar(pcar);xSemaphoreTake(g_xSemTicks,portMAX_DELAY);while (1){/* 读取按键值:读队列 *///xQueueReceive(xQueueIR, &idata, portMAX_DELAY);/* 控制汽车往右移动 *///if (idata.val == pcar->control_key){if (pcar->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(pcar);/* 调整位置 */pcar->x +=10 ;if (pcar->x > g_xres - CAR_LENGTH){pcar->x = g_xres - CAR_LENGTH;}/* 重新显示汽车 */ShowCar(pcar);vTaskDelay(50);if(pcar->x==g_xres-CAR_LENGTH){xSemaphoreGive(g_xSemTicks);vTaskDelete(NULL);}}}}
}void car_game(void)
{int x;int i, j;g_framebuffer = LCD_GetFrameBuffer(&g_xres, &g_yres, &g_bpp);draw_init();draw_end();g_xSemTicks  =xSemaphoreCreateBinary();xSemaphoreGive(g_xSemTicks);xSemaphoreGive(g_xSemTicks);xSemaphoreGive(g_xSemTicks);/* 画出路标 */for (i = 0; i < 3; i++){for (j = 0; j < 8; j++){draw_bitmap(16*j, 16+17*i, roadMarking, 8, 1, NOINVERT, 0);draw_flushArea(16*j, 16+17*i, 8, 1);}}/* 创建3个汽车任务 */
#if 0	for (i = 0; i < 3; i++){draw_bitmap(g_cars[i].x, g_cars[i].y, carImg, 15, 16, NOINVERT, 0);draw_flushArea(g_cars[i].x, g_cars[i].y, 15, 16);}
#endifxTaskCreate(CarTask, "car1", 128, &g_cars[0], osPriorityNormal, NULL);xTaskCreate(CarTask, "car2", 128, &g_cars[1], osPriorityNormal, NULL);xTaskCreate(CarTask, "car3", 128, &g_cars[2], osPriorityNormal, NULL);	
}

优先级反转

static void CarTask1(void *params)
{struct car *pcar = params;struct ir_data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 显示汽车 */ShowCar(pcar);xSemaphoreTake(g_xSemTicks,portMAX_DELAY);while (1){/* 读取按键值:读队列 *///xQueueReceive(xQueueIR, &idata, portMAX_DELAY);/* 控制汽车往右移动 *///if (idata.val == pcar->control_key){if (pcar->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(pcar);/* 调整位置 */pcar->x +=5 ;if (pcar->x > g_xres - CAR_LENGTH){pcar->x = g_xres - CAR_LENGTH;}/* 重新显示汽车 */ShowCar(pcar);vTaskDelay(50);if(pcar->x==g_xres-CAR_LENGTH){xSemaphoreGive(g_xSemTicks);vTaskDelete(NULL);}}}}
}
static void CarTask2(void *params)
{struct car *pcar = params;struct ir_data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 显示汽车 */ShowCar(pcar);vTaskDelay(1000);//xSemaphoreTake(g_xSemTicks,portMAX_DELAY);while (1){/* 读取按键值:读队列 *///xQueueReceive(xQueueIR, &idata, portMAX_DELAY);/* 控制汽车往右移动 *///if (idata.val == pcar->control_key){if (pcar->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(pcar);/* 调整位置 */pcar->x +=4 ;if (pcar->x > g_xres - CAR_LENGTH){pcar->x = g_xres - CAR_LENGTH;}/* 重新显示汽车 */ShowCar(pcar);mdelay(50);if(pcar->x==g_xres-CAR_LENGTH){//xSemaphoreGive(g_xSemTicks);//vTaskDelete(NULL);}}}}
}
static void CarTask3(void *params)
{struct car *pcar = params;struct ir_data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 显示汽车 */ShowCar(pcar);vTaskDelay(2000);xSemaphoreTake(g_xSemTicks,portMAX_DELAY);while (1){/* 读取按键值:读队列 *///xQueueReceive(xQueueIR, &idata, portMAX_DELAY);/* 控制汽车往右移动 *///if (idata.val == pcar->control_key){if (pcar->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(pcar);/* 调整位置 */pcar->x +=4 ;if (pcar->x > g_xres - CAR_LENGTH){pcar->x = g_xres - CAR_LENGTH;}/* 重新显示汽车 */ShowCar(pcar);vTaskDelay(50);if(pcar->x==g_xres-CAR_LENGTH){xSemaphoreGive(g_xSemTicks);vTaskDelete(NULL);}}}}
}void car_game(void)
{int x;int i, j;g_framebuffer = LCD_GetFrameBuffer(&g_xres, &g_yres, &g_bpp);draw_init();draw_end();g_xSemTicks  =xSemaphoreCreateBinary();xSemaphoreGive(g_xSemTicks);xSemaphoreGive(g_xSemTicks);xSemaphoreGive(g_xSemTicks);/* 画出路标 */for (i = 0; i < 3; i++){for (j = 0; j < 8; j++){draw_bitmap(16*j, 16+17*i, roadMarking, 8, 1, NOINVERT, 0);draw_flushArea(16*j, 16+17*i, 8, 1);}}/* 创建3个汽车任务 */
#if 0	for (i = 0; i < 3; i++){draw_bitmap(g_cars[i].x, g_cars[i].y, carImg, 15, 16, NOINVERT, 0);draw_flushArea(g_cars[i].x, g_cars[i].y, 15, 16);}
#endifxTaskCreate(CarTask1, "car1", 128, &g_cars[0], osPriorityNormal, NULL);xTaskCreate(CarTask2, "car2", 128, &g_cars[1], osPriorityNormal+2, NULL);xTaskCreate(CarTask3 , "car3", 128, &g_cars[2], osPriorityNormal+3 , NULL);	
}

互斥量

互斥量(Mutex,Mutual Exclusion)是一种用于同步的机制,主要用于控制对共享资源的访问,确保同一时间只有一个线程或任务能够访问该资源。这在多线程或多任务环境中非常重要,以避免数据竞争和不一致的问题。

互斥量(Mutex)是用于保护共享资源的一种同步机制,通常用于防止多个任务同时访问同一个资源,从而避免数据竞争和不一致性。在 FreeRTOS 中,互斥量是一种特殊类型的信号量,它提供了更强的排他性。

互斥量的特点

  1. 独占性:一次只有一个任务可以拥有互斥量。如果一个任务已经获得了互斥量,其他任务必须等待,直到该互斥量被释放。
  2. 优先级继承:如果一个低优先级任务持有互斥量,而一个高优先级任务试图获取该互斥量,低优先级任务的优先级会暂时提升到高优先级任务的级别,从而减少优先级反转的风险。
  3. 适用于保护共享资源:互斥量常用于保护共享数据或资源,以确保数据的完整性。

互斥量的基本工作原理:

  1. 获取和释放

    • 当一个任务需要访问共享资源时,它会尝试获取互斥量。
    • 如果互斥量当前未被其他任务占用,任务成功获取互斥量并可以安全地访问资源。
    • 如果互斥量已被其他任务占用,当前任务会被阻塞,直到互斥量被释放。
  2. 释放互斥量

    • 当任务完成对资源的操作后,它会释放互斥量,使其他被阻塞的任务能够获取该互斥量并访问资源。

使用互斥量的优势:

  • 数据一致性:通过确保只有一个任务在任何时刻访问共享资源,互斥量可以避免数据冲突和不一致性。
  • 避免死锁:如果设计得当,互斥量可以减少或避免死锁情况的发生。

注意事项:

  • 性能开销:频繁地获取和释放互斥量可能会导致性能下降,因此在设计时要考虑优化。
  • 死锁风险:如果多个任务相互等待对方释放互斥量,可能会导致系统死锁。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【STL_list 模拟】——打造属于自己的高效链表容器

一、list节点 ​ list是一个双向循环带头的链表&#xff0c;所以链表节点结构如下&#xff1a; template<class T>struct ListNode{T val;ListNode* next;ListNode* prve;ListNode(int x){val x;next prve this;}};二、list迭代器 2.1、list迭代器与vector迭代器区别…

VLAN间通信以及ospf配置

目录 1.基础知识介绍 1.1 什么是VLAN&#xff1f; 1.2 VLAN有什么用&#xff1f; 1.3 不同VLAN如何实现通信&#xff1f; 1.4 什么是路由汇总&#xff1f; 1.4.1 路由汇总的好处&#xff1a; 2. 实验 2.1 网络拓扑设计 2.2 实验配置要求 2.2.1 三层交换配置&#xff…

UE4_Niagara基础实例—13、通过纹理采样来创造粒子

效果&#xff1a; 知识点&#xff1a; 1、纹理采样目前仅支持GPU粒子运行&#xff08;Texture sampling is only supported on the GPU at the moment.&#xff09; 2、网格位置输出每个粒子在网格中的归一化位置。我们使用该值来采样纹理&#xff0c;就像它是UV一样&#xff…

前段(vue)

目录 跨域是什么&#xff1f; SprinBoot跨域的三种解决方法 JavaScript 有 8 种数据类型&#xff0c; 金额的用什么类型。 前段 区别 JQuery使用$.ajax()实现异步请求 Vue 父子组件间的三种通信方式 Vue2 和 Vue3 存在多方面的区别。 跨域是什么&#xff1f; 跨域是指…

基于SpringBoot+Vue实现智能停车收费系统

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

私有化视频平台EasyCVR海康大华宇视视频平台视频诊断技术是如何实时监测视频质量的?

在现代视频监控系统中&#xff0c;确保视频流的质量和稳定性至关重要。随着技术的进步&#xff0c;视频诊断技术已经成为实时监测视频质量的关键工具。这种技术通过智能分析算法对视频流进行实时评估和处理&#xff0c;能够自动识别视频中的各种质量问题&#xff0c;并给出相应…

Linux云计算 |【第五阶段】CLOUD-DAY10

主要内容&#xff1a; 部署Dashboard、部署Prometheus、部署HPA集群 一、Dashboard介绍 Dashboard是基于网页的Kubernetes用户界面&#xff0c;可以使用Dashboard将容器应用部署到Kubernetes集群中&#xff0c;也可以对容器应用排错&#xff0c;还能管理集群资源。可以使用Da…

无人机避障——4D毫米波雷达Octomap从点云建立三维栅格地图

Octomap安装 sudo apt-get install ros-melodic-octomap-ros sudo apt-get install ros-melodic-octomap-msgs sudo apt-get install ros-melodic-octomap-server sudo apt-get install ros-melodic-octomap-rviz-plugins # map_server安装 sudo apt-get install ros-melodic-…

【GIN】go-gin 中 validator 验证功能

文章目录 前言一、基础用法二、常用字段说明常用字段说明1. required2. len3. min 和 max4. gte 和 lte 、 gt 和 lt 、ne5. oneof6. email7. url 三、示例代码运行效果 总结 前言 在 Go 中使用 Gin 框架时&#xff0c;BindJSON 可以将 JSON 请求体中的数据绑定到结构体上&…

使用Jupyter Notebook进行数据科学项目

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Jupyter Notebook进行数据科学项目 Jupyter Notebook 简介 安装 Jupyter Notebook 创建和管理 Notebook 编写和运行代码 示例…

【MyBatis源码】CacheKey缓存键的原理分析

文章目录 Mybatis缓存设计缓存KEY的设计CacheKey类主体CacheKey组成CacheKey如何保证缓存key的唯一性 Mybatis缓存设计 MyBatis 每秒过滤众多数据库查询操作&#xff0c;这对 MyBatis 缓存键的设计提出了很高的要求。MyBatis缓存键要满足以下几点。 无碰撞&#xff1a;必须保证…

一键式配置适合 Web 开发的Ubuntu系统

大家好&#xff0c;今天给大家分享一个专为Ubuntu设计的Web开发者配置方案Omakub。 项目介绍 Omakub是一个为开发者打造的、经过精心配置的 Ubuntu 环境项目&#xff0c;由 Ruby on Rails 的创造者 David Heinemeier Hansson&#xff08;DHH&#xff09;发起。目的是为了简化他…

Nginx安装配置详解

Nginx Nginx官网 Tengine翻译的Nginx中文文档 轻量级的Web服务器&#xff0c;主要有反向代理、负载均衡的功能。 能够支撑5万的并发量&#xff0c;运行时内存和CPU占用低&#xff0c;配置简单&#xff0c;运行稳定。 写在前 uWSGI与Nginx的关系 1. 安装 Windows 官网 Stabl…

数据库 二

一.数据认识 1.关系型 表与表的关系&#xff1a;核心表 mysql/oracle、SQLServer(微软) SQL 2.非关系型 redis--缓存数据库Map<k,v> NO-SQL&#xff1a;not only sql 二.关系型数据库(R) 1.客户端、数据库服务 2.库(database) CREATE DATABASE xxx_db;//创建库 DR…

开源OCR免费助力法律文档数字化,提升文档管理效率

一、在法律行业&#xff0c;每天需要处理大量纸质文件&#xff0c;从合同到判决书&#xff0c;手动录入不仅费时&#xff0c;还容易出错。为解决这一问题推出了一款免费开源的OCR智能识别平台&#xff0c;通过先进的光学字符识别&#xff08;OCR&#xff09;技术&#xff0c;将…

零售EDI:HornBach EDI 项目案例

HornBach 是一家总部位于德国的家居和建筑材料零售商&#xff0c;成立于1968年。它以大型仓储式商店而闻名&#xff0c;提供广泛的产品&#xff0c;包括建筑材料、园艺、家居装饰和工具等。 近期我们帮助HornBach的供应商W公司成功实现了与HornBach的EDI直连&#xff0c;除了满…

jupyter如何切换内核

01、写在前面 Jupyter是一个开源的交互式笔记本工具&#xff0c;支持多种编程语言&#xff0c;包括Python、R、Julia 等。它最初是作为IPython 笔记本的一个分支而开发的&#xff0c;后来逐渐发展成为一个独立的项目。Jupyter的名字来源于它支持的三种编程语言&#xff1a;Juli…

STM32ZET6-USART使用

一、原理说明 STM32自带通讯接口 通讯目的 通信方式&#xff1a; 全双工&#xff1a;通信时可以双方同时通信。 半双工&#xff1a;通信时同一时间只能一个设备发送数据&#xff0c;其他设备接收。 单工&#xff1a;只能一个设备发送到另一个设备&#xff0c;例如USART只有…

动态库实现lua网络请求GET, POST, 下载文件

DLL需要使用的网络封装 WinHttp异步实现GET, POST, 多线程下载文件_webclient post下载文件-CSDN博客文章浏览阅读726次。基于WinHttp封装, 实现异步多线程文件下载, GET请求, POST请求_webclient post下载文件https://blog.csdn.net/Flame_Cyclone/article/details/142644088…

牛客周赛65(C++实现)

比赛链接&#xff1a;牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ 文章目录 1.超市1.1 题目描述1.2 思路1.3 代码 2. 雨幕2.1 题目描述2.2 思路2.3 代码 3.闺蜜3.1 题目描述3.2 思路3.3 代码 4. 医生4.1 题目描述4.2 思路4.3 代码 1.超市 1.1 题目描述 …