互斥信号量的等待与通知

devtools/2025/1/12 19:18:26/

目录

等待互斥信号量

信号量未被占用

信号量被自己占用

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

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

释放互斥信号量

未发生优先级继承

发生优先级继承


等待互斥信号量

信号量未被占用
  • 标记为已经占用
  • 锁定计数+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.ppmy.cn/devtools/149949.html

相关文章

基于Linux环境的进度条实现

文章目录 前言&#x1f4da;一、预备知识&#x1f4d6;1.1 回车换行&#x1f4d6;1.2 缓冲区 &#x1f4da;二、倒计时&#x1f4d6;2.1 源代码&#x1f4d6;2.2 效果展示&#x1f4d6;2.3 注意事项&#xff1a; &#x1f4da;三、进度条&#x1f4d6;3.1 源代码&#x1f4d3;p…

微信小程序中使用weui组件库

这里只介绍官方推荐的通过useExtendedLib扩展库的方式引入&#xff0c;这种方式引入的组件将不计入代码包的大小。 app.json中配置 {"useExtendedLib": {"kbone": true,"weui": true} }在使用组件的页面的 json 文件加入 usingComponents 配置字…

jmeter使用说明

一、新建一个测试计划 二、右键测试计划&#xff0c;添加线程组 三、配置线程组 0、配置请求前预处理程序 可以进行参数加签加密等操作。&#xff08;有需求请求参数需要加密加签等操作的可以配置&#xff0c;无需求的可以不配置&#xff09; 添加BeanShell预处理程序 ${__P(…

【HarmonyOS Next NAPI 深度探索1】Node.js 和 CC++ 原生扩展简介

【HarmonyOS Next NAPI 深度探索1】Node.js 和 CC 原生扩展简介 如果你用过 Node.js&#xff0c;应该知道它强大的地方在于能处理各种场景&#xff0c;速度还很快。但你有没有想过&#xff0c;Node.js 的速度秘密是什么&#xff1f;今天我们来聊聊其中一个幕后英雄——原生扩展…

C++ STL map和set的使用

序列式容器和关联式容器 想必大家已经接触过一些容器如&#xff1a;list&#xff0c;vector&#xff0c;deque&#xff0c;array&#xff0c;forward_list&#xff0c;string等&#xff0c;这些容器统称为系列容器。因为逻辑结构为线性的&#xff0c;两个位置的存储的值一般是…

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

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

1.微服务

商城项目源码地址 https://gitee.com/huyi612/hmall 使用jmeter测试高并发 传统单体项目的弊端 案例&#xff1a;如果某一个请求耗时太长会把tomcat的资源给占完了&#xff0c;导致其他请求进来耗时更长&#xff0c;甚至无法进入。 RestController RequestMapping("h…

基于人脸识别和 MySQL 的考勤管理系统实现

在现代企业和机构中&#xff0c;考勤管理系统是日常运营中不可或缺的一部分。传统的考勤方式&#xff08;如打卡、指纹识别等&#xff09;有时会因为各种原因导致管理效率低下或员工作弊。然而&#xff0c;随着人脸识别技术的飞速发展&#xff0c;基于人脸识别的考勤管理系统正…