互斥信號量的等待與通知

目錄

等待互斥信號量

信號量未被占用

信號量被自己占用

信號量被高優先級任務占用

信號量被低優先級任務占用

釋放互斥信號量

未發生優先級繼承

發生優先級繼承


等待互斥信號量

信號量未被占用
  • 標記為已經占用
  • 鎖定計數+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.pswp.cn/web/65771.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/65771.shtml
英文地址,請注明出處:http://en.pswp.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; 主要用于網頁內容的動態修改和交互&…

Qt資源文件以及文件加密

1、Qt資源文件 在Qt中&#xff0c;資源文件&#xff08;.qrc&#xff09;是一種方便的方式來管理應用程序中的多媒體文件&#xff0c;如圖像、圖標和其他資源。這些文件使用XML格式定義&#xff0c;并在編譯時嵌入到應用程序的二進制文件中。 創建資源文件的步驟如下&#xff…

深入詳解人工智能自然語言處理(NLP)之文本處理:分詞、詞性標注、命名實體識別

【自然語言處理】——深入詳解人工智能自然語言處理&#xff08;NLP&#xff09;之文本處理&#xff1a;分詞、詞性標注、命名實體識別 自然語言處理&#xff08;Natural Language Processing&#xff0c;簡稱NLP&#xff09;是人工智能的一個重要分支&#xff0c;涉及如何使計…

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

文章目錄 老照片修復上色SD模型Node節點工作流程開發與應用效果展示老照片修復上色 該工作流專門設計用于老照片的修復和上色,通過一系列高級的圖像處理技術,包括深度圖預處理、面部修復、上色和圖像放大等步驟,來恢復老照片的質量并增加色彩。首先,工作流加載老照片并進行…

后端技術選型 sa-token校驗學習 下 結合項目學習 前后端登錄

目錄 后端設置 Controller 層 Service 層 后端返回 Token 給前端 1. 用戶提交登錄請求 2. 后端驗證用戶身份 3. 返回 Token 4. 前端保存 Token 前端存儲 1. 前端向后端發起請求 2. 前端存儲一下 Token 3.管理用戶認證的 token 的 工具 4. 在 Service 層進行設置 H…

dtdug匯編指令練習

r 通用寄存器 m 代表內存 imm 代表立即數 r8 代表8位通用寄存器 m8 代表8位內存 imm8 代表8位立即數 mov指令練習 MOV 的語法: mov 目標操作數&#xff0c;源操作數 作用:拷貝源操作數到目標操作數 1、源操作數可以是立即數、通用寄存器、段寄存器、或者內存單元. 2、目標操作數…

vue3模板引用ref

1.訪問模板引用 要在組合式 API 中獲取引用&#xff0c;我們可以使用輔助函數 useTemplateRef() 只可以在組件掛載后才能訪問模板引用 <script setup> import { useTemplateRef, onMounted } from vue// 第一個參數必須與模板中的 ref 值匹配 const input useTempla…

如何用 SSH 訪問 QNX 虛擬機

QNX 虛擬機默認是開啟 SSH 服務的&#xff0c;如果要用 SSH 訪問 QNX 虛擬機&#xff0c;就需要知道虛擬機的 IP 地址&#xff0c;用戶和密碼。本文我們來看看如何獲取這些參數。 1. 啟動虛擬機 啟動過程很慢&#xff0c;請耐心等待。 2. 查看 IP 地址 等待 IDE 連接到虛擬機。…

【Java基礎】Java異常捕捉,throws/throw、finally、try、catch關鍵字的含義與運用

1. Java 異常處理&#xff1a; 異常是程序中的一些錯誤&#xff0c;但并不是所有的錯誤都是異常&#xff0c;并且錯誤有時候是可以避免的。 比如說&#xff0c;你的代碼少了一個分號&#xff0c;那么運行出來結果是提示是錯 java.lang.Error&#xff1b;如果你用System.out.p…

js 中堆、棧、隊列+宏任務+微任務+web workers

文章目錄 js 中堆、棧、隊列介紹js中 堆、棧、隊列的區別與應用拓展&#xff08;宏任務與微任務&#xff09;Web Workers js 中堆、棧、隊列介紹 棧&#xff08;Stack&#xff09; 概念&#xff1a; 棧是一種遵循后進先出&#xff08;LIFO - Last In First Out&#xff09;原則…

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;更換阿里云鏡像和中央倉庫都沒辦法…

谷歌開放語音命令數據集,助力初學者踏入音頻識別領域

在人工智能的浪潮中&#xff0c;語音識別技術正逐漸成為我們日常生活的一部分。從智能助手到語音控制設備&#xff0c;語音識別的應用場景越來越廣泛。然而&#xff0c;對于初學者來說&#xff0c;進入這一領域往往面臨諸多挑戰&#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]…

字節小米等后端崗位C++面試題

C 基礎 引用和指針之間的區別&#xff1f;堆棧和堆中的內存分配有何區別&#xff1f;存在哪些類型的智能指針&#xff1f;unique_ptr 是如何實現的&#xff1f;我們如何強制在 unique_ptr 中僅存在一個對象所有者&#xff1f;shared_ptr 如何工作&#xff1f;對象之間如何同步…

極狐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…