互斥信号量的等待与通知

news2025/1/12 23:21:15

目录

等待互斥信号量

信号量未被占用

信号量被自己占用

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

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

释放互斥信号量

未发生优先级继承

发生优先级继承


等待互斥信号量

信号量未被占用
  • 标记为已经占用
  • 锁定计数+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);//插入到事件控制块是用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;
}

/* 事件控制块通知函数(将任务从事件控制块中唤醒,唤醒队列中的指定任务) */
//参数:事件控制块,指定唤醒的任务,消息,唤醒结果
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.coloradmin.cn/o/2275695.html

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

相关文章

rom定制系列------小米max3安卓12 miui14批量线刷 默认开启usb功能选项 插电自启等

小米Max3是小米公司于2018年7月19日发布的机型。此机型后在没有max新型号。采用全金属一体机身设计&#xff0c;配备6.9英寸全面屏.八核处理器骁龙636&#xff0c;后置双摄像头1200万500万像素&#xff0c;前置800万像素.机型代码 &#xff1a;nitrogen.官方最终版为稳定版12.5…

Linux第一课:c语言 学习记录day06

四、数组 冒泡排序 两两比较&#xff0c;第 j 个和 j1 个比较 int a[5] {5, 4, 3, 2, 1}; 第一轮&#xff1a;i 0 n&#xff1a;n个数&#xff0c;比较 n-1-i 次 4 5 3 2 1 // 第一次比较 j 0 4 3 5 2 1 // 第二次比较 j 1 4 3 2 5 1 // 第三次比较 j 2 4 3 2 1 5 // …

Cline(原Claude Dev)开源的IDE AI插件,如何搭配OpenRouter实现cursor功能,Cline怎么使用

Cline&#xff08;原Claude Dev&#xff09;是一个开源的IDE AI插件&#xff0c;可以使用你的命令行界面和编辑器的人工智能助手。 你可以直接在VS Code编辑器进行安装。如果你使用过Cursor AI IDE的话&#xff0c;可以尝试最新发布的Cline3.1版本。 在OpenRouter上&#xff0…

arcgis的合并、相交、融合、裁剪、联合、标识操作的区别和使用

1、相交 需要输入两个面要素&#xff0c;最终得到的是两个输入面要素相交部分的结果面要素。 2、合并 合并能将两个单独存放的两个要素类的内容&#xff0c;汇集到一个要素类里面。 3、融合 融合能将一个要素类内的所有元素融合成一个整体。 4、裁剪 裁剪需要输入两个面要…

【Rust自学】11.7. 按测试的名称运行测试

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 11.7.1. 按名称运行测试的子集 如果想要选择运行的测试&#xff0c;就将测试的名称&#xff08;一个或多个&#xff09;作为cargo test的…

利用Java爬虫获取义乌购店铺所有商品列表:技术探索与实践

在当今数字化时代&#xff0c;数据的重要性不言而喻。对于采购商和市场分析师而言&#xff0c;能够快速获取并分析供应商店铺内的所有商品信息&#xff0c;是制定有效采购策略和市场分析的关键。义乌购作为国内知名的在线批发平台&#xff0c;拥有海量的商品数据。本文将介绍如…

An FPGA-based SoC System——RISC-V On PYNQ项目复现

本文参考&#xff1a; &#x1f449; 1️⃣ 原始工程 &#x1f449; 2️⃣ 原始工程复现教程 &#x1f449; 3️⃣ RISCV工具链安装教程 1.准备工作 &#x1f447;下面以LOCATION代表本地源存储库的安装目录&#xff0c;以home/xilinx代表在PYNQ-Z2开发板上的目录 ❗ 下载Vivad…

Photoshop PS批处理操作教程(批量修改图片尺寸、参数等)

前言 ‌Photoshop批处理的主要作用‌是通过自动化处理一系列相似的操作来同时应用于多张图片&#xff0c;从而节省时间和精力&#xff0c;提高工作效率。批处理功能特别适用于需要批量处理的任务&#xff0c;如图像尺寸调整、颜色校正、水印添加等‌。 操作步骤 1.创建动作 …

互联网架构变迁:从 TCP/IP “呼叫” 到 NDN “内容分发” 的逐浪之旅

本文将给出关于互联网架构演进的一个不同视角。回顾一下互联网的核心理论基础产生的背景&#xff1a; 左边是典型的集中控制通信网络&#xff0c;很容易被摧毁&#xff0c;而右边的网络则没有单点问题&#xff0c;换句话说它很难被全部摧毁&#xff0c;与此同时&#xff0c;分…

nvim 打造成可用的IDE(2)

上一个 文章写的太长了&#xff0c; 后来再写东西 就一卡一卡的&#xff0c;所以新开一个。 主要是关于 bufferline的。 之前我的界面是这样的。 这个图标很不舒服有。 后来发现是在这里进行配置。 我也不知道&#xff0c;这个配置 我是从哪 抄过来的。 测试结果&#xff1…

drawDB docker部属

docker pull xinsodev/drawdb docker run --name some-drawdb -p 3000:80 -d xinsodev/drawdb浏览器访问&#xff1a;http://192.168.31.135:3000/

Redis--20--大Key问题解析

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 大Key问题1.什么是 Redis 大 Key&#xff1f;在 Redis 中&#xff0c;大 Key 是指单个键值对的数据量非常大&#xff0c;可能包含大量数据。 2. Redis大Key的危害3.…

自动驾驶---E2E架构演进

1 背景 模型最早应用的自动驾驶模块就是感知层面&#xff0c;随着技术的发展&#xff0c;逐渐开始应用到决策规划等其它模块。端到端自动驾驶架构是一种基于深层神经网络模型和方法的自动驾驶技术模式。目前一段式端到端系统只有在英伟达早期所做的demo中实现&#xff0c;再者就…

如何优雅地绘制时序图

说到时序图&#xff0c;相信所有从事嵌入式开发的伙伴都非常熟悉&#xff0c;在各种元器件手册以及处理器说明书中&#xff0c;但凡涉及到通信、接口、交互等内容&#xff0c;都会涉及到时序图。时序图可以非常详细且明确地描述硬件及软件接口中各个信号的时序关系&#xff0c;…

SpringCloud系列教程:微服务的未来(十一)服务注册、服务发现、OpenFeign快速入门

本篇博客将通过实例演示如何在 Spring Cloud 中使用 Nacos 实现服务注册与发现&#xff0c;并使用 OpenFeign 进行服务间调用。你将学到如何搭建一个完整的微服务通信框架&#xff0c;帮助你快速开发可扩展、高效的分布式系统。 目录 前言 服务注册和发现 服务注册 ​编辑 …

WebGIS在应急灾害中对村庄、风景区、机场的影响范围应用-以日喀则市定日县地震为例

目录 前言 一、关于影响范围 1、震中距离5公里 2、震中20公里范围 3、20到80公里范围 二、空间查询知识 1、相关数据介绍 2、空间数据查询 三、前后端数据查询以及web可视化实现 1、后台API实现 2、WebGIS前端实现 四、Web成果展示 1、空间位置分析 2、包含风景区…

使用网页版Jupyter Notebook和VScode打开.ipynb文件

目录 正文 1、网页版Jupyter Notebook查看 2、VScode查看 因为总是忘记查看文件的网址&#xff0c;收藏了但分类众多每次都找不到……当个记录吧&#xff08;/捂脸哭&#xff09;&#xff01; 正文 此处以gitub中的某个仓库为例&#xff1a; https://github.com/INM-6/mu…

景联文科技提供高质量多模态数据处理服务,驱动AI新时代

在当今快速发展的AI时代&#xff0c;多模态数据标注成为推动人工智能技术进步的关键环节。景联文科技作为行业领先的AI数据服务提供商&#xff0c;专注于为客户提供高质量、高精度的多模态数据标注服务&#xff0c;涵盖图像、语音、文本、视频及3D点云等多种类型的数据。通过专…

Python在Excel工作表中创建数据透视表

在数据处理和分析工作中&#xff0c;Excel作为一个广泛使用的工具&#xff0c;提供了强大的功能来管理和解析数据。当面对大量复杂的数据集时&#xff0c;为了更高效地总结、分析和展示数据&#xff0c;创建数据透视表成为一种不可或缺的方法。通过使用Python这样的编程语言与E…

django基于Python的电影推荐系统

Django 基于 Python 的电影推荐系统 一、系统概述 Django 基于 Python 的电影推荐系统是一款利用 Django 框架开发的智能化应用程序&#xff0c;旨在为电影爱好者提供个性化的电影推荐服务。该系统通过收集和分析用户的观影历史、评分数据、电影的属性信息&#xff08;如类型…