FreeRTOS Semaphore信號量-筆記

FreeRTOS Semaphore信號量-筆記

      • **一、信號量與互斥量的核心區別**
      • **二、二值信號量(Binary Semaphore)**
        • **1. 功能與使用場景**
        • **2. 示例:ADC中斷與任務同步**
      • **三、計數信號量(Counting Semaphore)**
        • **1. 功能與使用場景**
        • **2. 示例:ADC雙緩沖區管理**
      • **四、互斥量(Mutex)**
        • **1. 功能與使用場景**
        • **2. 示例:保護共享資源**
      • **五、關鍵注意事項**
      • **六、總結**

在這里插入圖片描述


隊列的功能是將進程間需要傳遞的數據存在其中。所以在有的RTOS系統里,隊列也被稱為郵箱。

一、信號量與互斥量的核心區別

特性信號量(Semaphore)互斥量(Mutex)
用途進程間同步(如事件通知)或資源計數(如ADC雙緩沖區)互斥訪問共享資源(如保護全局變量或外設)
所有權無所有權(任何任務或ISR均可釋放)有所有權(僅持有者可釋放)
優先級繼承機制(可能導致優先級翻轉)(緩解優先級翻轉)
是否可中斷使用(通過 xSemaphoreGiveFromISR不可(ISR中無法使用)
初始值二值信號量(0或1)或計數信號量(任意值)固定為1(表示資源可用)

信號量和互斥量。信號量和互斥量的實現都是基于隊列的,信號量更適用于進程間同步,而互斥量更適用于共享資源的互斥性訪問。
在這里插入圖片描述


二、二值信號量(Binary Semaphore)

在這里插入圖片描述
如果不使用二值信號量,而是使用一個自定義標志變量來實現以上的同步過程,則任務需要不斷的查詢標志變量的值,而不是像使用二值信號那樣可以使任務進入阻塞動態狀態。所以使用二值信號量進行進程間同步的效率更高。

1. 功能與使用場景
  • 功能:作為“標志”實現任務同步,例如:
    • ADC中斷通知任務:當ADC中斷寫入緩沖區后,釋放二值信號量通知任務處理數據。
    • 任務等待事件:任務阻塞等待信號量,避免忙等待。
  • 創建函數
  // 動態分配xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE );//這是一個宏函數。調用的函數類似于隊列(xQueueGenericCreate)創建隊列時,調用的也是這個函數。

參數解析

  • ( UBaseType_t ) 1

    • 隊列長度:表示隊列最多能容納的“消息”數量。
    • 二進制信號量特性:二進制信號量只能處于“空”(0)或“滿”(1)狀態,因此隊列長度設為 1。
  • semSEMAPHORE_QUEUE_ITEM_LENGTH

    • 隊列項大小:定義隊列中每個消息的字節長度。
    • 二進制信號量特殊性:該宏被定義為 0(#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U )),表示信號量不存儲實際數據,僅用隊列的空/滿狀態表示信號量狀態。
  • queueQUEUE_TYPE_BINARY_SEMAPHORE

    • 隊列類型:指定此隊列用于二進制信號量,而非普通隊列或其他類型(如互斥鎖或計數信號量)。

  // 靜態分配SemaphoreHandle_t xSemaphoreCreateBinaryStatic(StaticSemaphore_t *pxSemaphoreBuffer);
  • 操作函數
    • 釋放信號量(任務):
    xSemaphoreGive( xSemaphore )    xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )

參數解析

  • (QueueHandle_t)(xSemaphore)

    • 信號量即隊列:FreeRTOS 的信號量句柄 xSemaphore 實際上是隊列句柄(QueueHandle_t)的別名。信號量通過隊列實現,其行為由隊列的配置參數控制(如長度、項大小等)。
  • NULL

    • 無實際數據:信號量本身不傳遞數據,僅用隊列的空/滿狀態表示信號量狀態。因此,發送的“消息”無需有效數據,使用 NULL 即可。
  • semGIVE_BLOCK_TIME

    • 阻塞時間:定義為 0(#define semGIVE_BLOCK_TIME (0)),表示調用 xSemaphoreGive 時不等待。如果隊列已滿(信號量已處于“可用”狀態),則直接返回錯誤 errQUEUE_FULL。
  • queueSEND_TO_BACK

    • 入隊位置:將“消息”添加到隊列的尾部。信號量的順序無關緊要,因此使用尾部入隊是合理的。
  • 返回類型為BaseType_t,pdFALSE或者pdTRUE。


  • 釋放信號量(ISR):
xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken )    xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )

參數解析

  • xSemaphore
    • 信號量句柄:實際是一個隊列句柄(QueueHandle_t)的別名。信號量通過隊列實現,其行為由隊列的配置參數控制(如長度、項大小等)。
  • pxHigherPriorityTaskWoken
    • 優先級喚醒標志:
    • 類型:BaseType_t *(指向布爾值的指針)。
    • 功能:如果釋放信號量導致更高優先級的任務被喚醒,該指針會被設置為 pdTRUE,表示需要在退出中斷前請求上下文切換。
    • 可選參數:從 FreeRTOS V7.3.0 開始,此參數可以設為 NULL。
    • 注意:如果釋放信號量導致了一個任務解鎖,而解鎖的任務比當前任務的優先級高,這里就會返回pdTRUE。這就需要在退出ISR之前申請任務調度,以便及時的解鎖高優先級的任務。

在這里插入圖片描述


  • 獲取信號量(任務):
xSemaphoreTake( xSemaphore, xBlockTime )    xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )

參數解析

  • xSemaphore
  • 信號量句柄:實際是一個隊列句柄(QueueHandle_t)的別名。信號量通過隊列實現,其行為由隊列的配置參數控制(如長度、項大小等)。
  • 類型:SemaphoreHandle_t(底層為 QueueHandle_t)。
    ● xBlockTime
  • 阻塞時間:以 Tick 為單位指定任務等待信號量的最長時間。
  • portMAX_DELAY:無限期等待,直到信號量可用。
  • 0:非阻塞模式,立即返回。
  • 轉換:使用 pdMS_TO_TICKS(ms) 將毫秒轉換為 Tick(例如 pdMS_TO_TICKS(100))。

2. 示例:ADC中斷與任務同步
// 創建二值信號量
SemaphoreHandle_t xADCSemaphore = xSemaphoreCreateBinary();// ADC中斷服務程序
void ADC_IRQHandler(void) {// 寫入數據到緩沖區WriteDataToBuffer();// 釋放信號量通知任務xSemaphoreGiveFromISR(xADCSemaphore, NULL);
}// 數據處理任務
void vDataProcessingTask(void *pvParameters) {while (1) {// 等待信號量xSemaphoreTake(xADCSemaphore, portMAX_DELAY);// 處理緩沖區數據ProcessData();}
}

三、計數信號量(Counting Semaphore)

在這里插入圖片描述
資源類比成一個餐館中的四個餐桌。
管理多個共享資源。例如ADC連續數據采集時,一般使用雙緩沖區,就可以使用計數信號量來進行管理。

1. 功能與使用場景
  • 功能:管理多個同類型資源(如ADC雙緩沖區),允許同時訪問多個資源。
  • 創建函數
    // 動態分配
    SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);
    // 靜態分配
    SemaphoreHandle_t xSemaphoreCreateCountingStatic(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer);
    
  • 操作函數
    • 釋放資源
      xSemaphoreGive(xSemaphore);  // 資源計數+1
      
    • 獲取資源
      xSemaphoreTake(xSemaphore, xTicksToWait);  // 資源計數-1
      
2. 示例:ADC雙緩沖區管理
// 創建計數信號量(2個緩沖區)
SemaphoreHandle_t xADCBufferSemaphore = xSemaphoreCreateCounting(2, 2);// ADC中斷服務程序
void ADC_IRQHandler(void) {// 獲取一個緩沖區if (xSemaphoreTakeFromISR(xADCBufferSemaphore, NULL) == pdTRUE) {// 寫入數據到緩沖區WriteDataToBuffer();// 釋放信號量(資源可用)xSemaphoreGiveFromISR(xADCBufferSemaphore, NULL);}
}// 數據處理任務
void vDataProcessingTask(void *pvParameters) {while (1) {// 獲取緩沖區資源xSemaphoreTake(xADCBufferSemaphore, portMAX_DELAY);// 處理緩沖區數據ProcessData();// 釋放緩沖區資源xSemaphoreGive(xADCBufferSemaphore);}
}

四、互斥量(Mutex)

在這里插入圖片描述
在這里插入圖片描述

二值信號量更適用于進程間同步,而互斥量更適用于控制對互斥型資源的訪問。二值信號量沒有優先級繼承機制,將二值信號量用于互斥型資源訪問時,容易出現優先級翻轉問題。而互斥量有優先級繼承機制,可以減緩優先級翻轉問題。

1. 功能與使用場景
  • 功能:保護共享資源的獨占訪問(如串口),避免數據競爭。
  • 創建函數
    // 動態分配
    SemaphoreHandle_t xSemaphoreCreateMutex(void);
    // 靜態分配
    SemaphoreHandle_t xSemaphoreCreateMutexStatic(StaticSemaphore_t *pxSemaphoreBuffer);
    
  • 操作函數
    • 釋放互斥量(可以釋放二值信號量、計數信號量或者是互斥量。)
      xSemaphoreGive(xSemaphore);
      
    • 獲取互斥量
      xSemaphoreTake(xSemaphore, xTicksToWait);
      
    • 遞歸互斥量(允許任務多次獲取同一互斥量):
      // 創建
      SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void);
      // 釋放
      xSemaphoreGiveRecursive(xSemaphore);
      // 獲取
      xSemaphoreTakeRecursive(xSemaphore, xTicksToWait);
      
2. 示例:保護共享資源
// 創建互斥量
SemaphoreHandle_t xSharedResourceMutex = xSemaphoreCreateMutex();// 任務A
void vTaskA(void *pvParameters) {while (1) {xSemaphoreTake(xSharedResourceMutex, portMAX_DELAY);// 訪問共享資源SharedResource++;xSemaphoreGive(xSharedResourceMutex);}
}// 任務B
void vTaskB(void *pvParameters) {while (1) {xSemaphoreTake(xSharedResourceMutex, portMAX_DELAY);// 訪問共享資源SharedResource--;xSemaphoreGive(xSharedResourceMutex);}
}

五、關鍵注意事項

  1. 優先級翻轉問題

    • 二值信號量:無優先級繼承機制,可能導致低優先級任務阻塞高優先級任務。
    • 互斥量:通過優先級繼承機制緩解問題,但仍需謹慎設計任務優先級。
  2. ISR中的使用限制

    • 信號量:可在ISR中使用(xSemaphoreGiveFromISR)。
    • 互斥量禁止在ISR中使用(因其依賴優先級繼承)。
  3. 內存分配選擇

    • 動態分配:適合資源充足的系統,但可能產生內存碎片。
    • 靜態分配:適合資源受限的嵌入式系統,需手動管理內存。
  4. 調試工具

    • uxSemaphoreGetCount():獲取信號量當前值(適用于計數信號量)。
    • xSemaphoreGetMutexHolder():檢查互斥量當前持有者。

六、總結

其他相關函數
● xSemaphoreGiveRecursive(用于遞歸互斥鎖的釋放)。
●xSemaphoreTakeRecursive()獲取二值信號量、計數信號量或者是互斥量。釋放遞歸互斥量依然有一個專用的函數。
●uxSemaphoreGetCount()返回傳進去的這個信號量的當前值。
●xSemaphoreGetMutexHolder()作用:返回當前持有指定互斥鎖(mutex)的任務的句柄(TaskHandle)。如果互斥鎖未被任何任務持有,則返回 NULL。
xSemaphoreTakeFromISR()

  • 選擇信號量還是互斥量
    • 同步需求(如事件通知)→ 信號量
    • 資源互斥訪問(如保護共享變量)→ 互斥量
  • 避免常見錯誤
    • 不要在ISR中釋放互斥量。
    • 確保每次獲取互斥量后最終釋放。
    • 使用遞歸互斥量時,獲取與釋放需嚴格配對。

通過合理使用信號量和互斥量,可以高效實現FreeRTOS中的任務同步與資源共享,提升系統的實時性和穩定性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82519.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82519.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82519.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

音頻類網站或者資訊總結

我愛音頻網: 我愛音頻網 - 我們只談音頻,豐富的TWS真無線藍牙耳機拆解報告 (52audio.com) 其他更多資訊 音頻行業全品類深度剖析,2024市場趨勢解讀匯總-EDN 電子技術設計 (ednchina.com)

16.Excel:數據收集

一 使用在線協作工具 簡道云。 excel的在線表格協作在國內無法使用,而數據采集最需要在線協作。 二 使用 excel 1.制作表格 在使用excel進行數據采集的時候,會制作表頭給填寫人,最好還制作一個示例。 1.輸入提示 當點擊某個單元格的時候&am…

JAVA虛擬機(JVM)總結,很清晰,很好理解!!

目錄 java編譯相關知識 Java文件編譯過程 java的可跨平臺性 JVM內存結構 運行期數據區域(JDK8之后) 本地方法棧 虛擬方法棧 程序計數器 堆 本地內存 棧幀里面的局部變量表和方法區(元空間的區別) 類加載器 啟動類加載…

前端項目中單元測試與集成測試的管理實踐

前端項目中單元測試與集成測試的管理實踐 在現代前端工程化中,單元測試(Unit Test)和集成測試(Integration Test)已成為保障項目質量的重要手段。合理地組織和管理測試代碼,不僅有助于持續集成&#xff0c…

【Redis】緩存和分布式鎖

🔥個人主頁: 中草藥 🔥專欄:【中間件】企業級中間件剖析 一、緩存(Cache) 概述 Redis最主要的應用場景便是作為緩存。緩存(Cache)是一種用于存儲數據副本的技術或組件,…

深入解析路由策略:從流量控制到策略實施

一、網絡流量雙平面解析 在路由策略的設計中,必須明確區分兩個關鍵平面: 1. 控制層面(Control Plane) ??定義??:路由協議傳遞路由信息形成的邏輯平面(如OSPF的LSA、RIP的Response報文)?…

從杰夫?托爾納看 BPLG 公司的技術創新與發展

在科技與商業緊密交織的時代,企業的技術領導者在推動組織前行、應對復雜多變的市場環境中扮演著極為關鍵的角色。《對話 CTO,駕馭高科技浪潮》的第 6 章聚焦于杰夫?托爾納及其所在的 BPLG 公司,為我們展現了一幅技術驅動企業發展的生動圖景&…

UniRepLknet助力YOLOv8:高效特征提取與目標檢測性能優化

文章目錄 一、引言二、UniRepLknet 的框架原理(一)架構概述(二)架構優勢 三、UniRepLknet 在 YOLOv8 中的集成(一)集成方法(二)代碼實例 四、實驗與對比(一)對…

比較Facebook與其他社交平臺的隱私保護策略

在這個數字化的時代,隱私保護已成為用戶和社交平臺共同關注的核心議題。Facebook,作為全球最大的社交網絡平臺之一,其隱私保護策略一直受到廣泛的關注和討論。本文將對Facebook的隱私保護策略與其他社交平臺進行比較,以幫助用戶更…

數據結構--樹

一、樹的概念 樹是由n(n≥0)個節點組成的有限集合,它滿足以下條件: 1. 當n0時,稱為空樹 2. 當n>0時,有且僅有一個特定的節點稱為根節點(root) 3. 其余節點可分為m(m≥0)個互不相交的有限集合,每個集合本身又是一…

Linux `ifconfig` 指令深度解析與替代方案指南

Linux `ifconfig` 指令深度解析與替代方案指南 一、核心功能與現狀1. 基礎作用2. 版本適配二、基礎語法與常用操作1. 標準語法2. 常用操作速查顯示所有接口信息啟用/禁用接口配置IPv4地址修改MAC地址(臨時)三、高級配置技巧1. 虛擬接口創建2. MTU調整3. 多播配置4. ARP控制四…

什么是分布式光伏系統?屋頂分布式光伏如何并網?

政策窗口倒計時!分布式光伏如何破局而立? 2025年,中國分布式光伏行業迎來關鍵轉折: ? "430"落幕——搶裝潮收官,但考驗才剛開始; ? "531"生死線——新增項目全面市場化交易啟動&…

Cluster Interconnect in Oracle RAC

Cluster Interconnect in Oracle RAC (文檔 ID 787420.1)?編輯轉到底部 In this Document Purpose Scope Details Physical Layout of the Private Interconnect Why Do We Need a Private Interconnect ? Interconnect Failure Interconnect High Availability Private Inte…

.Net HttpClient 使用準則

HttpClient 使用準則 System.Net.Http.HttpClient 類用于發送 HTTP 請求以及從 URI 所標識的資源接收 HTTP 響應。 HttpClient 實例是應用于該實例執行的所有請求的設置集合,每個實例使用自身的連接池,該池將其請求與其他請求隔離開來。 從 .NET Core …

【PostgreSQL】數據庫主從庫備份與高可用部署

文章目錄 一、架構設計原理二、部署清單示例2.1 StatefulSet配置片段2.2 Service配置三、配置詳解3.1 主節點postgresql.conf3.2 從節點配置四、初始化流程4.1 創建復制用戶4.2 配置pg_hba.conf五、故障轉移示例5.1 自動切換腳本5.2 手動提升從節點六、監控與維護6.1 關鍵監控指…

JavaScript 數組去重:11 種方法對比與實戰指南

文章目錄 前言一、使用 Set 數據結構二、使用 filter indexOf三、使用 reduce 累加器四、雙重 for 循環五、利用對象屬性唯一性六、先排序后去重七、使用 Map 數據結構八、使用 includes 方法九、優化處理 NaN 的 filter 方法十、利用 findIndex十一.利用Set和展開運算符處理多…

ai agent(智能體)開發 python3基礎14:在python 中 總能看到方法里面套方法,那什么時候用這種方式合適呢?

讓人頭疼的方法嵌套還是要去了解的 在 Python 中,方法內部嵌套方法(即在類的方法中定義另一個函數)是一種常見的代碼組織技巧,它可以在特定場景下帶來以下好處: 1. 代碼復用與邏輯封裝 如果某個方法內部有重復的邏輯…

Yocto項目實戰經驗總結:從入門到高級的全面概覽

本文面向開發者和實際項目經驗者,分享經過大量實戰積累的 Yocto 項目工程經驗和基礎技巧。本文簡明但精彩,應用和觀察相結合,充分適合做為全面進階 Yocto 項目開發的實用指南。 一、入門理解:Yocto 是什么?規劃如何開始…

添加物體.

在cesium中我們可以添加物體進入地圖.我們以廣州塔為例 //生成廣州塔的位置var position2 Cesium.Cartesian3.fromDegrees(113.3191,23.109,100)viewer.camera.setView({//指定相機位置destination: position2, 運行后如圖 我們使用cesium官網提供的代碼為廣州塔在地圖上標點…

正則表達式非捕獲分組?:

一個使用 Java 正則表達式的具體例子,展示了 (ab) 和 (?:ab) 的不同: 示例 1:使用 (ab)(捕獲分組) import java.util.regex.*; public class RegexExample { public static void main(String[] args) { …