互斥信号量的等待与通知

目录

等待互斥信号量

信号量未被占用

信号量被自己占用

信号量被高优先级任务占用

信号量被低优先级任务占用

释放互斥信号量

未发生优先级继承

发生优先级继承


等待互斥信号量

信号量未被占用
  • 标记为已经占用
  • 锁定计数+1
信号量自己占用
  • 锁定计数+1
信号量被高优先级任务占用
  • 低优先级任务插入事件控制块等待队列
信号量低优先级任务占用
  • 高优先级任务插入等待队列
  • 低优先级任务设置高优先级任务一样的优先级

释放互斥信号量

未发生优先级继承
  • 释放信号量
  • 等待队列唤醒一个任务占用信号量
发生优先级继承
  • 低优先级任务信号量释放不再占用信号量同时低优先级任务优先级改为原有优先级
  • 等待队列唤醒一个任务占用信号量

tMutex.c

#include "tinyOS.h"/* 互斥信号量初始化函数 */
void tMutexInit(tMutex *mutex)
{tEventInit(&mutex->event, tEventTypeMutex);mutex->lockedCount = 0;mutex->owner = (tTask *)0;mutex->ownerOriginalPrio = TINYOS_PRO_COUNT;//初始设为无效值
}/* 等待互斥信号量函数 */
//参数:互斥信号量,超时时间
uint32_t tMutexWait(tMutex *mutex, uint32_t waitTicks)
{uint32_t status = tTaskEnterCritical();//互斥信号量是否被锁定if(mutex->lockedCount <= 0){//未锁定:当前任务可以占用互斥信号量mutex->owner = currentTask;mutex->ownerOriginalPrio = currentTask->prio;mutex->lockedCount++;tTaskExitCritical(status);return tErrorNoError;}else{//已锁定://判断是否是当前任务锁定的if(mutex->owner == currentTask){mutex->lockedCount++;tTaskExitCritical(status);return tErrorNoError;}else{//不是当前任务锁定://判断当前任务优先级和互斥信号量占有者优先级哪个高if(currentTask->prio < mutex->owner->prio){//当前任务优先级高://任务优先级继承机制tTask *owner = mutex->owner;//判断当前任务是否为就绪状态if(owner->state == TINYOS_TASK_STATE_RDY){//当前任务为就绪状态:tTaskSchedUnRdy(owner);//从原有就绪队列中移出owner->prio = currentTask->prio;//更改所有者优先级tTaskSchedRdy(owner);//插入新的队列}else{owner->prio = currentTask->prio;}}tEventWait(&mutex->event, currentTask, (void *)0, tEventTypeMutex, waitTicks);//当前任务插入事件控制块中tTaskExitCritical(status);tTaskSched();return currentTask->waitEventResult;}}
}/* 无等待获取互斥信号量函数 */
//仅需检查互斥信号量能否被当前任务获取到
uint32_t tMutexNoWaitGet(tMutex *mutex)
{uint32_t status = tTaskEnterCritical();//判断互斥信号量是否被锁定if(mutex->lockedCount <= 0){//没有被锁定:由当前任务锁定mutex->owner = currentTask;mutex->ownerOriginalPrio = currentTask->prio;mutex->lockedCount++;tTaskExitCritical(status);return tErrorNoError;}else{//被锁定://判断互斥信号量所有者是否是当前任务if(mutex->owner == currentTask){mutex->lockedCount++;tTaskExitCritical(status);return tErrorNoError;}tTaskExitCritical(status);return tErrorResourceUnavailable;}
}/* 释放互斥信号量函数 */
uint32_t tMutexNotify(tMutex *mutex)
{uint32_t status = tTaskEnterCritical();//判断信号量是否被锁定if(mutex->lockedCount <= 0){tTaskExitCritical(status);return tErrorNoError;}//判断信号量所有者if(mutex->owner != currentTask){tTaskExitCritical(status);return tErrorOwner;}//对锁定计数--仍大于0:没有到最终释放任务的过程if(--mutex->lockedCount > 0){tTaskExitCritical(status);return tErrorNoError;}//判断是否发生优先级继承if(mutex->ownerOriginalPrio != mutex->owner->prio){//发生优先级继承://判断任务是否在就绪状态if(mutex->owner->state == TINYOS_TASK_STATE_RDY){//更改任务所在就绪列表位置及优先级tTaskSchedUnRdy(mutex->owner);currentTask->prio = mutex->ownerOriginalPrio;tTaskSchedUnRdy(mutex->owner);}else{currentTask->prio = mutex->ownerOriginalPrio;}}//判断当前等待队列中是否有任务if(tEventWaitCount(&mutex->event) > 0){tTask *task = tEventWakeUp(&mutex->event, (void *)0, tErrorNoError);//取出一个任务//信号量的所有者设置为新任务mutex->owner = task;mutex->ownerOriginalPrio = task->prio;mutex->lockedCount++;//判断任务的优先级是否比当前任务的优先级高if(task->prio < currentTask->prio){tTaskSched();}}tTaskExitCritical(status);return tErrorNoError;
}

tMutex.h

#ifndef __TMUTEX_H
#define __TMUTEX_H#include "tEvent.h"/* 互斥信号量结构 */
typedef struct _tMutex
{tEvent event;								//事件控制块uint32_t lockedCount;				//锁定计数器tTask *owner;								//当前互斥信号量所有者uint32_t ownerOriginalPrio;	//所有者原始优先级
}tMutex;void tMutexInit(tMutex *mutex);
uint32_t tMutexWait(tMutex *mutex, uint32_t waitTicks);
uint32_t tMutexNoWaitGet(tMutex *mutex);
uint32_t tMutexNotify(tMutex *mutex);#endif

tintOS.h

#ifndef __TINYOS_H
#define __TINYOS_H#include <stdint.h>
#include "tLib.h"
#include "tConfig.h"
#include "tTask.h"
#include "tEvent.h"
#include "tSem.h"
#include "tMbox.h"
#include "tMemBlock.h"
#include "tFlagGroup.h"
#include "tMutex.h"/* 错误码 */
typedef enum _tError{tErrorNoError = 0,				//没有错误发生tErrorTimeout,						//超时tErrorResourceUnavailable,//资源不可用tErrorDel,								//被删除tErrorResourceFull,				//资源已满tErrorOwner,							//拥有者错误
}tError;extern tTask *currentTask;			
extern tTask *nextTask;				uint32_t tTaskEnterCritical(void);
void tTaskExitCritical(uint32_t status);void tTaskSwitch(void);		//和CPU相关,写在switch.c
void tTaskRunFirst(void);void tTaskSchedInit(void);
void tTaskSchedDisable(void);
void tTaskSchedEnable(void);
void tTaskSchedRdy(tTask *task);
void tTaskSchedUnRdy(tTask *task);
void tTaskSchedRemove(tTask *task);
void tTaskSched(void);
void tTimeTaskWait(tTask *task, uint32_t ticks);
void tTimeTaskWakeUp(tTask *task);
void tTimeTaskRemove(tTask *task);
void tTaskSystemTickHandler(void);
void tTaskDelay(uint32_t delay);void tSetSysTickPeriod(uint32_t ms);
void tInitApp(void);#endif

tEvent.c

#include "tinyOS.h"/* 事件控制块初始化函数 */
void tEventInit(tEvent *event, tEventType type)
{event->type = tEventTypeUnknow;tListInit(&event->waitList);
}/* 事件控制块等待函数 */
//参数:事件控制块,任务,消息(传入消息来源,在事件发生以后存放具体的消息),等待的状态,超时时间
void tEventWait(tEvent *event, tTask *task, void *msg, uint32_t state, uint32_t timeout)
{uint32_t status = tTaskEnterCritical();task->state |= state << 16;task->waitEvent = event;task->eventMsg = msg;task->waitEventResult = tErrorNoError;tTaskSchedUnRdy(task);//移出就绪队列tListAddLast(&event->waitList, &task->linkNode);//插入事件控制块等待队列的尾部if(timeout){tTimeTaskWait(task, timeout);//设置了超时事件,插入延时队列}tTaskExitCritical(status);
}/* 事件控制块通知函数(将任务从事件控制块中唤醒,唤醒队列首部任务) */
//参数:事件控制块,消息,唤醒结果
tTask *tEventWakeUp(tEvent *event, void *msg, uint32_t result)
{tNode *node;tTask *task = (tTask *)0;uint32_t status = tTaskEnterCritical();if((node = tListRemoveFirst(&event->waitList)) != (tNode *)0){task = (tTask *)tNodeParent(node, tTask, linkNode);//插入到事件控制块是用linknodetask->waitEvent = (tEvent *)0;//不等待任何事件task->eventMsg = msg;task->waitEventResult = result;task->state &= ~TINYOS_TASK_WAIT_MASK;if(task->delayTicks != 0)//有延时{tTimeTaskWakeUp(task);//强制将任务从延时队列中移除}tTaskSchedRdy(task);//插入就绪队列}tTaskExitCritical(status);return task;
}/* 事件控制块通知函数(将任务从事件控制块中唤醒,唤醒队列中的指定任务) */
//参数:事件控制块,指定唤醒的任务,消息,唤醒结果
tTask *tEventWakeUpTask(tEvent *event, tTask *task, void *msg, uint32_t result)
{uint32_t status = tTaskEnterCritical();tListRemove(&event->waitList, &task->linkNode);//直接将任务移出队列task->waitEvent = (tEvent *)0;//不等待任何事件task->eventMsg = msg;task->waitEventResult = result;task->state &= ~TINYOS_TASK_WAIT_MASK;if(task->delayTicks != 0)//有延时{tTimeTaskWakeUp(task);//强制将任务从延时队列中移除}tTaskSchedRdy(task);//插入就绪队列tTaskExitCritical(status);return task;
}/* 事件控制块移除函数 */
void tEventRemoveTask(tTask *task, void *msg, uint32_t result)
{uint32_t status = tTaskEnterCritical();tListRemove(&task->waitEvent->waitList, &task->linkNode);task->waitEvent = (tEvent *)0;task->eventMsg = msg;task->waitEventResult = result;task->state &= ~TINYOS_TASK_WAIT_MASK;tTaskExitCritical(status);
}/* 事件控制块清空函数 */
//返回值:事件任务块被清空时,它的等待队列中有多少任务
uint32_t tEventRemoveAll(tEvent *event, void *msg, uint32_t result)
{tNode *node;uint32_t count = 0;uint32_t status = tTaskEnterCritical();count = tListCount(&event->waitList);//等待队列中有多少任务while((node = tListRemoveFirst(&event->waitList)) != (tNode *)0)//移除等待队列头部任务{tTask *task = (tTask *)tNodeParent(node, tTask, linkNode);//获取task结构task->waitEvent = (tEvent *)0;//不再等待事件task->eventMsg = msg;task->waitEventResult = result;task->state &= ~TINYOS_TASK_WAIT_MASK;if(task->delayTicks != 0)//任务有延时{tTimeTaskWakeUp(task);//移出延时队列}tTaskSchedRdy(task);}tTaskExitCritical(status);return count;
}/* 获取事件控制块中等待任务函数 */
uint32_t tEventWaitCount(tEvent *event)
{uint32_t count = 0;uint32_t status = tTaskEnterCritical();count = tListCount(&event->waitList);tTaskExitCritical(status);return count;
}

app.c

#include "tinyOS.h"
#include "string.h"//定义任务,分别为它们配备独立的堆栈空间
tTask tTask1;
tTask tTask2;
tTask tTask3;
tTask tTask4;
tTaskStack task1Env[1024];
tTaskStack task2Env[1024];
tTaskStack task3Env[1024];
tTaskStack task4Env[1024];tMutex mutex;//定义任务要执行的功能
int task1Flag;
void task1Entry(void *param)
{tSetSysTickPeriod(10);//初始化tMutexInit(&mutex);for(;;)//任务里是for的死循环{//嵌套的申请互斥信号量再释放tMutexWait(&mutex, 0);tMutexWait(&mutex, 0);task1Flag = 0; tTaskDelay(1);task1Flag = 1;tTaskDelay(1);tMutexNotify(&mutex);tMutexNotify(&mutex);}
}int task2Flag;
void task2Entry(void *param)
{for(;;){tMutexWait(&mutex, 0);tMutexWait(&mutex, 0);task2Flag = 0;tTaskDelay(1);task2Flag = 1;tTaskDelay(1);tMutexNotify(&mutex);tMutexNotify(&mutex);}
}
int task3Flag;
void task3Entry(void *param)
{for(;;){task3Flag = 0;tTaskDelay(1);task3Flag = 1;tTaskDelay(1);}
}
int task4Flag;
void task4Entry(void *param)
{for(;;){task4Flag = 0;tTaskDelay(1);task4Flag = 1;tTaskDelay(1);}
}/* 应用任务初始化函数 */
void tInitApp(void)
{//最后一个参数:传堆栈末端地址,因为堆栈是向下生长的,初始堆栈地址是堆栈空间最后一个单元地址的末端tTaskInit(&tTask1, task1Entry, (void *)0x11111111, 0, &task1Env[1024]);tTaskInit(&tTask2, task2Entry, (void *)0x22222222, 1, &task2Env[1024]);tTaskInit(&tTask3, task3Entry, (void *)0x22222222, 1, &task3Env[1024]);tTaskInit(&tTask4, task4Entry, (void *)0x22222222, 1, &task4Env[1024]);
}

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

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

相关文章

夯实前端基础之HTML篇

知识点概览 HTML部分 1. DOM和BOM有什么区别&#xff1f; DOM&#xff08;Document Object Model&#xff09; 当网页被加载时&#xff0c;浏览器会创建页面的对象文档模型&#xff0c;HTML DOM 模型被结构化为对象树 用途&#xff1a; 主要用于网页内容的动态修改和交互&…

SD ComfyUI工作流 老照片修复上色

文章目录 老照片修复上色SD模型Node节点工作流程开发与应用效果展示老照片修复上色 该工作流专门设计用于老照片的修复和上色,通过一系列高级的图像处理技术,包括深度图预处理、面部修复、上色和图像放大等步骤,来恢复老照片的质量并增加色彩。首先,工作流加载老照片并进行…

后端技术选型 sa-token校验学习 下 结合项目学习 前后端登录

目录 后端设置 Controller 层 Service 层 后端返回 Token 给前端 1. 用户提交登录请求 2. 后端验证用户身份 3. 返回 Token 4. 前端保存 Token 前端存储 1. 前端向后端发起请求 2. 前端存储一下 Token 3.管理用户认证的 token 的 工具 4. 在 Service 层进行设置 H…

如何用 SSH 访问 QNX 虚拟机

QNX 虚拟机默认是开启 SSH 服务的&#xff0c;如果要用 SSH 访问 QNX 虚拟机&#xff0c;就需要知道虚拟机的 IP 地址&#xff0c;用户和密码。本文我们来看看如何获取这些参数。 1. 启动虚拟机 启动过程很慢&#xff0c;请耐心等待。 2. 查看 IP 地址 等待 IDE 连接到虚拟机。…

java面向对象编程特性概述

目录 1. 类和对象 2. 封装&#xff08;Encapsulation&#xff09; 3. 继承&#xff08;Inheritance&#xff09; 4. 多态&#xff08;Polymorphism&#xff09; 5. 抽象&#xff08;Abstraction&#xff09; (1). 抽象类&#xff08;Abstract Class&#xff09; (2).接口…

React(二)——Admin主页/Orders页面/Category页面

文章目录 项目地址一、侧边栏1.1 具体实现 二、Header2.1 实现 三、Orders页面3.1 分页和搜索3.2 点击箭头显示商家所有订单3.3 页码按钮以及分页 四、Category页面4.1 左侧商品添加栏目4.2 右侧商品上传栏 五、Sellers页面六、Payment Request 页面&#xff08;百万数据加载&a…

maven 下载依赖 jhash:2.1.2 和对应 jar 包

原文地址 前言 25年新的一年&#xff0c;那就先更新一篇技术文章吧&#xff0c;这个是这几天刚遇到的一个有意思的bug&#xff0c;记录分享一下 原因分析 在使用maven加载一个项目的时&#xff0c;发现maven的依赖一直无法解析&#xff0c;更换阿里云镜像和中央仓库都没办法…

nums[:]数组切片

问题&#xff1a;给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 使用代码如下没有办法通过测试示例&#xff0c;必须将最后一行代码改成 nums[:]nums[-k:]nums[:-k]切片形式&#xff1a; 原因&#xff1a;列表的切片操作 …

python-leetcode-三数之和

15. 三数之和 - 力扣&#xff08;LeetCode&#xff09; class Solution:def threeSum(self, nums: List[int]) -> List[List[int]]:nums.sort() # 排序n len(nums)res []for i in range(n):# 剪枝&#xff1a;如果当前数 > 0&#xff0c;三数之和不可能为 0if nums[i]…

极狐GitLab 正式发布安全版本17.7.1、17.6.3、17.5.5

本分分享极狐GitLab 补丁版本 17.7.1, 17.6.3, 17.5.5 的详细内容。这几个版本包含重要的缺陷和安全修复代码&#xff0c;我们强烈建议所有私有化部署用户应该立即升级到上述的某一个版本。对于极狐GitLab SaaS&#xff0c;技术团队已经进行了升级&#xff0c;无需用户采取任何…

探索绿色能源系统的固态继电器:2025年展望

随着全球向绿色能源转型的加速&#xff0c;对高效、可靠和环保元件的需求从未如此强烈。在这种背景下&#xff0c;国产固态继电器(SSR)在实现太阳能逆变器、风力涡轮机和储能系统等关键技术方面发挥着关键作用。本文探讨了绿色能源系统背景下中国固态继电器行业的前景&#xff…

Rust语言使用iced实现简单GUI页面

使用cargo新建一个rust项目 cargo new gui_demo cd gui_demo 编辑Cargo.toml文件 ,添加iced依赖 [package] name "gui_demo" version "0.1.0" edition "2021"[dependencies] iced "0.4.2" 编辑src/main.rs文件&#xff1a; u…

Github提交Pull Request教程 Git基础扫盲(零基础易懂)

1 PR是什么&#xff1f; PR&#xff0c;全称Pull Request&#xff08;拉取请求&#xff09;&#xff0c;是一种非常重要的协作机制&#xff0c;它是 Git 和 GitHub 等代码托管平台中常见的功能&#xff0c;被广泛用于参与社区贡献&#xff0c;从而促进项目的发展。 PR的整个过…

RabbitMQ 可观测性最佳实践

RabbitMQ 简介 RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写&#xff0c;支持多种客户端。它通过使用交换机&#xff08;Exchanges&#xff09;、队列&#xff08;Queues&#xff09;和绑定&#xff08;Bindings&#xff09;来路由消息&#xff…

美摄科技PC端视频编辑解决方案,为企业打造专属的高效创作平台

在当今这个信息爆炸的时代&#xff0c;视频已成为不可或缺的重要内容形式&#xff0c;美摄科技推出了PC端视频编辑解决方案的私有化部署服务&#xff0c;旨在为企业提供一款量身定制的高效创作平台。 一、全面功能&#xff0c;满足企业多样化需求 美摄科技的PC端视频编辑解决…

【Oracle篇】深入了解执行计划中的访问路径(含表级别、B树索引、位图索引、簇表四大类访问路径)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;从事IT领域✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控&#xff1b;并对SQLserver、NoSQL(…

腾讯云AI代码助手编程挑战赛-厨房助手之AI大厨

腾讯云AI代码助手编程挑战赛-厨房助手之AI大厨 作品简介 身处当今如火箭般迅猛发展的互联网时代&#xff0c;智能聊天助手已然化身成为提升用户体验的关键利器&#xff0c;全方位渗透至人们的数字生活。 紧紧跟随着这股汹涌澎湃的时代浪潮&#xff0c;我毅然投身于极具挑战性…

vscode 无法使用npm, cmd命令行窗口可以正常执行

解决方法&#xff1a; 执行命令获得命令的位置 get-command npm 得到如下 然后删除或者修改 npm.ps1文件 让其不能使用就行。然后重启vscode即可。 pnpm 同理即可 另外加速源 国内镜像源&#xff08;淘宝&#xff09;&#xff1a; npm config set registry https://regist…

简易CPU设计入门:算术逻辑单元(四)

项目代码下载 请大家首先准备好本项目所用的源代码。如果已经下载了&#xff0c;那就不用重复下载了。如果还没有下载&#xff0c;那么&#xff0c;请大家点击下方链接&#xff0c;来了解下载本项目的CPU源代码的方法。 CSDN文章&#xff1a;下载本项目代码 上述链接为本项目…

Spring Boot 和微服务:快速入门指南

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…