精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

詳解互斥信號量的概念和運行

開源嵌入式 ? 來源:開源嵌入式 ? 作者:開源嵌入式 ? 2020-10-22 11:57 ? 次閱讀

1 、互 斥 信 號 量

1.1 互斥信號量的概念及其作用

互斥信號量的主要作用是對資源實現互斥訪問,使用二值信號量也可以實現互斥訪問的功能,不過互斥信號量與二值信號量有區別。下面我們先舉一個通過二值信號量實現資源獨享,即互斥訪問的例子,讓大家有一個形象的認識,進而引出要講解的互斥信號量。

運行條件:

讓兩個任務 Task1 和 Task2 都運行串口打印函數 printf,這里我們就通過二值信號量實現對函數printf 的互斥訪問。如果不對函數 printf 進行互斥訪問,串口打印容易出現亂碼。

用計數信號量實現二值信號量只需將計數信號量的初始值設置為 1 即可。

代碼實現:

創建二值信號量

static SemaphoreHandle_t xSemaphore = NULL; * 函 數 名: AppObjCreate * 功能說明: 創建任務通信機制 * 形 參: 無 * 返 回 值: 無 static void AppObjCreate (void) {/* 創建二值信號量,首次創建信號量計數值是 0 */xSemaphore = xSemaphoreCreateBinary();if(xSemaphore == NULL) {/* 沒有創建成功,用戶可以在這里加入創建失敗的處理機制 */}/* 先釋放一次,將初始值改為 1,利用二值信號量實現互斥功能 */xSemaphoreGive(xSemaphore); }

? 通過二值信號量實現對 printf 函數互斥訪問的兩個任務

static void vTaskLED(void *pvParameters) { TickType_t xLastWakeTime;const TickType_t xFrequency = 300;/* 獲取當前的系統時間 */xLastWakeTime = xTaskGetTickCount();while(1) {/* 通過二值信號量實現資源互斥訪問,永久等待直到資源可用 */xSemaphoreTake(xSemaphore, portMAX_DELAY); printf("任務 vTaskLED 在運行 "); bsp_LedToggle(1); bsp_LedToggle(4); xSemaphoreGive(xSemaphore);/* vTaskDelayUntil 是絕對延遲,vTaskDelay 是相對延遲。*/vTaskDelayUntil(&xLastWakeTime, xFrequency); } } * 函 數 名: vTaskMsgPro * 功能說明: 實現對串口的互斥訪問 * 形 參: pvParameters 是在創建該任務時傳遞的形參 * 返 回 值: 無 * 優 先 級: 3 static void vTaskMsgPro(void *pvParameters) { TickType_t xLastWakeTime; const TickType_t xFrequency = 300; /* 獲取當前的系統時間 */xLastWakeTime = xTaskGetTickCount(); while(1) { /* 通過二值信號量實現資源互斥訪問,永久等待直到資源可用 */ xSemaphoreTake(xSemaphore, portMAX_DELAY); printf("任務 vTaskMsgPro 在運行 "); bsp_LedToggle(2); bsp_LedToggle(3); xSemaphoreGive(xSemaphore); /* vTaskDelayUntil 是絕對延遲,vTaskDelay 是相對延遲。*/ vTaskDelayUntil(&xLastWakeTime, xFrequency); } }

有了上面二值信號量的認識之后,互斥信號量與二值信號量又有什么區別呢?互斥信號量可以防止優先級翻轉,而二值信號量不支持,下面我們就講解一下優先級翻轉問題。

1.2 優先級翻轉問題

下面我們通過如下的框圖來說明一下優先級翻轉的問題,讓大家有一個形象的認識。


運行條件:

創建 3 個任務 Task1,Task2 和 Task3,優先級分別為 3,2,1。也就是 Task1 的優先級最高。
任務 Task1 和 Task3 互斥訪問串口打印 printf,采用二值信號實現互斥訪問。
起初 Task3 通過二值信號量正在調用 printf,被任務 Task1 搶占,開始執行任務 Task1,也就是上圖的起始位置。

運行過程描述如下:
任務 Task1 運行的過程需要調用函數 printf,發現任務 Task3 正在調用,任務 Task1 會被掛起,等待 Task3 釋放函數 printf。
在調度器的作用下,任務 Task3 得到運行,Task3 運行的過程中,由于任務 Task2 就緒,搶占了 Task3的運行。優先級翻轉問題就出在這里了,從任務執行的現象上看,任務 Task1 需要等待 Task2 執行完畢才有機會得到執行,這個與搶占式調度正好反了,正常情況下應該是高優先級任務搶占低優先級任務的執行,這里成了高優先級任務 Task1 等待低優先級任務 Task2 完成。所以這種情況被稱之為優先級翻轉問題。
任務 Task2 執行完畢后,任務 Task3 恢復執行,Task3 釋放互斥資源后,任務 Task1 得到互斥資源,從而可以繼續執行。

上面就是一個產生優先級翻轉問題的現象。

1.3 FreeRTOS 互斥信號量的實現

FreeRTOS 互斥信號量是怎么實現的呢?其實相對于二值信號量,互斥信號量就是解決了一下優先級翻轉的問題。下面我們通過如下的框圖來說明一下 FreeRTOS 互斥信號量的實現,讓大家有一個形象的認識。

運行條件:

創建 2 個任務 Task1 和 Task2,優先級分別為 1 和 3,也就是任務 Task2 的優先級最高。
任務 Task1 和 Task2 互斥訪問串口打印 printf。
使用 FreeRTOS 的互斥信號量實現串口打印 printf 的互斥訪問。

運行過程描述如下:

低優先級任務 Task1 執行過程中先獲得互斥資源 printf 的執行。此時任務 Task2 搶占了任務 Task1的執行,任務 Task1 被掛起。任務 Task2 得到執行。
任務 Task2 執行過程中也需要調用互斥資源,但是發現任務 Task1 正在訪問,此時任務 Task1 的優先級會被提升到與 Task2 同一個優先級,也就是優先級 3,這個就是所謂的優先級繼承(Priority inheritance),這樣就有效地防止了優先級翻轉問題。任務 Task2 被掛起,任務 Task1 有新的優先級繼續執行。
任務 Task1 執行完畢并釋放互斥資源后,優先級恢復到原來的水平。由于互斥資源可以使用,任務Task2 獲得互斥資源后開始執行。

上面就是一個簡單的 FreeRTOS 互斥信號量的實現過程。

1.4 FreeRTOS 中斷方式互斥信號量的實現

互斥信號量僅支持用在 FreeRTOS 的任務中,中斷函數中不可使用。

2 互 斥 信 號 量 API 函 數

使用如下 18 個函數可以實現 FreeRTOS 的信號量(含計數信號量,二值信號量和互斥信號):
? xSemaphoreCreateBinary()
? xSemaphoreCreateBinaryStatic()
? vSemaphoreCreateBinary()
? xSemaphoreCreateCounting()
? xSemaphoreCreateCountingStatic()
? xSemaphoreCreateMutex()
? xSemaphoreCreateMutexStatic()
? xSem'CreateRecursiveMutex()
? xSem'CreateRecursiveMutexStatic()
? vSemaphoreDelete()
? xSemaphoreGetMutexHolder()
? uxSemaphoreGetCount()
? xSemaphoreTake()
? xSemaphoreTakeFromISR()
? xSemaphoreTakeRecursive()
? xSemaphoreGive()
? xSemaphoreGiveRecursive()

? xSemaphoreGiveFromISR()

關于這 18 個函數的講解及其使用方法可以看 FreeRTOS 在線版手冊:

2.1 函數 xSemaphoreCreateMutex

函數原型:
SemaphoreHandle_t xSemaphoreCreateMutex( void )
函數描述:
函數 xSemaphoreCreateMutex 用于創建互斥信號量。
返回值,如果創建成功會返回互斥信號量的句柄,如果由于 FreeRTOSConfig.h 文件中 heap 大小不足,無法為此互斥信號量提供所需的空間會返回 NULL。

使用這個函數要注意以下問題:
1. 此函數是基于函數 xQueueCreateMutex 實現的:
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
函數 xQueueCreateMutex 的實現是基于消息隊列函數 xQueueGenericCreate 實現的。
2. 使用此函數要在 FreeRTOSConfig.h 文件中使能宏定義:
#define configUSE_MUTEXES 1

使用舉例:

static SemaphoreHandle_t xMutex = NULL; * 函 數 名: AppObjCreate * 功能說明: 創建任務通信機制 * 形 參: 無 * 返 回 值: 無 static void AppObjCreate (void) {/* 創建互斥信號量 */xMutex = xSemaphoreCreateMutex(); if(xSemaphore == NULL) {/* 沒有創建成功,用戶可以在這里加入創建失敗的處理機制 */} }

2.2 函數 xSemaphoreGive

函數原型:
xSemaphoreGive( SemaphoreHandle_t xSemaphore ); /* 信號量句柄 */
函數描述:
函數 xSemaphoreGive 用于在任務代碼中釋放信號量。
第 1 個參數是信號量句柄。
返回值,如果信號量釋放成功返回 pdTRUE,否則返回 pdFALSE,因為信號量的實現是基于消息隊列,返回失敗的主要原因是消息隊列已經滿了。
使用這個函數要注意以下問題:
1. 此函數是基于消息隊列函數 xQueueGenericSend 實現的:
#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME,queueSEND_TO_BACK )
2. 此函數是用于任務代碼中調用的,故不可以在中斷服務程序中調用此函數,中斷服務程序中使用的是xSemaphoreGiveFromISR。

3. 使用此函數前,一定要保證用函數 xSemaphoreCreateBinary(), xSemaphoreCreateMutex() 或者 xSemaphoreCreateCounting()創建了信號量。
4. 此函數不支持使用 xSemaphoreCreateRecursiveMutex()創建的信號量。

2.3 函數 xSemaphoreTake

函數原型:
xSemaphoreTake( SemaphoreHandle_t xSemaphore, /* 信號量句柄 */
TickType_t xTicksToWait ); /* 等待信號量可用的最大等待時間 */
函數描述:
函數 xSemaphoreTake 用于在任務代碼中獲取信號量。
第 1 個參數是信號量句柄。
第 2 個參數是沒有信號量可用時,等待信號量可用的最大等待時間,單位系統時鐘節拍。

返回值,如果創建成功會獲取信號量返回 pdTRUE,否則返回 pdFALSE。
使用這個函數要注意以下問題:
1. 此函數是用于任務代碼中調用的,故不可以在中斷服務程序中調用此函數,中斷服務程序使用的是xSemaphoreTakeFromISR。
2. 如果消息隊列為空且第 2 個參數為 0,那么此函數會立即返回。
3. 如果用戶將 FreeRTOSConfig.h 文件中的宏定義 INCLUDE_vTaskSuspend 配置為 1 且第 2 個參數配置為 portMAX_DELAY,那么此函數會永久等待直到信號量可用。

使用舉例:

static SemaphoreHandle_t xMutex = NULL; * 函 數 名: vTaskLED * 功能說明: 實現串口的互斥訪問,防止多個任務同時訪問造成串口打印亂碼 * 形 參: pvParameters 是在創建該任務時傳遞的形參 * 返 回 值: 無 * 優 先 級: 2 static void vTaskLED(void *pvParameters) { TickType_t xLastWakeTime;const TickType_t xFrequency = 200;/* 獲取當前的系統時間 */xLastWakeTime = xTaskGetTickCount();while(1) {/* 互斥信號量,xSemaphoreTake 和 xSemaphoreGive 一定要成對的調用 */xSemaphoreTake(xMutex, portMAX_DELAY); printf("任務 vTaskLED 在運行 "); bsp_LedToggle(2); bsp_LedToggle(3); xSemaphoreGive(xMutex);/* vTaskDelayUntil 是絕對延遲,vTaskDelay 是相對延遲。*/vTaskDelayUntil(&xLastWakeTime, xFrequency); } }

互斥信號量,xSemaphoreTake 和 xSemaphoreGive 一定要成對的調用

經過測試,互斥信號量是可以被其他任務釋放的,但是我們最好不要這么做,因為官方推薦的就是在同一個任務中接收和釋放。如果在其他任務釋放,不僅僅會讓代碼整體邏輯變得復雜,還會給使用和維護這套API的人帶來困難。遵守規范,總是好的。

裸機編程的時候,我經常想一個問題,就是怎么做到當一個標志位觸發的時候,立即執行某個操作,如同實現標志中斷一樣,在os編程之后,我們就可以讓一個優先級最高任務一直等待某個信號量,如果獲得信號量,就執行某個操作,實現類似標志位中斷的作用(當然,要想正真做到中斷效果,那就需要屏蔽所有可屏蔽中斷,而臨界區就可以做到)。

再說一下遞歸互斥信號量:遞歸互斥信號量,其實就是互斥信號量里面嵌套互斥信號量

使用舉例:

static void vTaskMsgPro(void *pvParameters) { TickType_t xLastWakeTime; const TickType_t xFrequency = 1500; /* 獲取當前的系統時間 */ xLastWakeTime = xTaskGetTickCount(); while(1) {/* 遞歸互斥信號量,其實就是互斥信號量里面嵌套互斥信號量 */ xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY); {//假如這里是被保護的資源,第1層被保護的資源,用戶可以在這里添加被保護資源 printf("任務vTaskMsgPro在運行,第1層被保護的資源,用戶可以在這里添加被保護資源 "); /* 第1層被保護的資源里面嵌套被保護的資源 */ xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY); { //假如這里是被保護的資源,第2層被保護的資源,用戶可以在這里添加被保護資源 printf("任務vTaskMsgPro在運行,第2層被保護的資源,用戶可以在這里添加被保護資源 "); /* 第2層被保護的資源里面嵌套被保護的資源 */ xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY); { printf("任務vTaskMsgPro在運行,第3層被保護的資源,用戶可以在這里添加被保護資源 "); bsp_LedToggle(1); bsp_LedToggle(4); } xSemaphoreGiveRecursive(xRecursiveMutex); } xSemaphoreGiveRecursive(xRecursiveMutex); } xSemaphoreGiveRecursive(xRecursiveMutex); /* vTaskDelayUntil是絕對延遲,vTaskDelay是相對延遲。*/ vTaskDelayUntil(&xLastWakeTime, xFrequency); } }

可以前面的那個官方文檔那樣用if判斷傳遞共享量:

也可以用我們遞歸互斥信號量里面的portMAX_DELAY指定永久等待,即xSemaphoreTakeRecursive返回的不是pdTRUE時,會一直等待信號量,直到有信號量來才執行后面的語句。

責任編輯:PSY

原文標題:嵌入式系統FreeRTOS — 互斥信號量

文章出處:【微信公眾號:開源嵌入式】歡迎添加關注!文章轉載請注明出處。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式系統
    +關注

    關注

    41

    文章

    3570

    瀏覽量

    129251
  • FreeRTOS
    +關注

    關注

    12

    文章

    483

    瀏覽量

    62018
  • 互斥信號量
    +關注

    關注

    0

    文章

    3

    瀏覽量

    2018
收藏 人收藏

    評論

    相關推薦

    開關和模擬的基本概念、特點及應用

    開關和模擬是電氣工程和自動化控制領域中的兩個重要概念。開關通常指二進制信號,即只有兩種狀態:開或關,高或低,1或0。模擬
    的頭像 發表于 08-30 11:10 ?643次閱讀

    熱控信號和保護裝置能否正常運行

    熱控信號和保護裝置是確保電力系統安全、穩定、經濟運行的重要手段。它們在電力系統中起著至關重要的作用,能夠及時檢測和處理各種異常情況,防止設備損壞和系統故障。 一、熱控信號和保護裝置的基本概念
    的頭像 發表于 08-27 11:12 ?268次閱讀

    PLC對模擬信號的處理過程及方法 詳解

    模擬信號是自動化過程控制系統中最基本的過程信號(壓力、溫度、流量等)輸入形式。系統中的過程信號通過變送器,將這些檢測信號轉換為統一的電壓、
    的頭像 發表于 07-30 16:31 ?345次閱讀
    PLC對模擬<b class='flag-5'>量</b><b class='flag-5'>信號</b>的處理過程及方法 <b class='flag-5'>詳解</b>版

    互斥鎖和自旋鎖的實現原理

    互斥鎖和自旋鎖是操作系統中常用的同步機制,用于控制對共享資源的訪問,以避免多個線程或進程同時訪問同一資源,從而引發數據不一致或競爭條件等問題。 互斥鎖(Mutex) 互斥鎖是一種基本的同步機制,用于
    的頭像 發表于 07-10 10:07 ?420次閱讀

    4到20ma模擬信號怎么測?及原理介紹

    模擬信號的測量方法、原理、特點以及注意事項。 ? ? ??一、4到20mA模擬信號的基本概念 ? ? ??1.1 4到20mA
    的頭像 發表于 06-23 08:38 ?4670次閱讀
    4到20ma模擬<b class='flag-5'>量</b><b class='flag-5'>信號</b>怎么測?及原理介紹

    4到20ma模擬信號怎么測

    的測量方法、原理、特點以及注意事項。 一、4到20mA模擬信號的基本概念 1.1 4到20mA信號的定義 4到20mA模擬
    的頭像 發表于 06-20 11:37 ?1605次閱讀

    使用STM32CUBEMX創建一個基于RTOS的工程,互斥創建不成功的原因?

    使用STM32CUBEMX創建一個基于RTOS的工程,使用了互斥,但互斥創建不成功
    發表于 05-15 07:22

    關于FreeRTOS互斥的用法求解

    對于串口發送,我們都普遍用中斷方式發送, 可是在配合互斥的時候會遇到些問題, 互斥的使用 必須在同一個任務中 占用和釋放, 我目前的做法是用二值
    發表于 04-24 08:03

    STM32F107+CubeMX+FreeRTOS+LWIP連接成功后,信號量無法使用怎么解決?

    各位大哥,遇到一個在FreeRTOS+LWIP使用信號量的問題。 項目工程是通過CubeMX生成的,使用FreeRTOS + LWIP。 簡化代碼,FreeRTOS初始化兩個任務,一個默認任務、一個
    發表于 04-19 07:33

    嵌入式實時操作系統——二值信號量

    當用戶需要使用停車資源時,它靠近屏障并按下請求按鈕,在信號量術語中,該行為被定義為信號等待(wait)操作。由于資源處于空閑狀態,故服務員抬起屏障并回答可以通過, 用戶隨即進入保護區域,然后屏障關閉。
    發表于 04-09 14:44 ?628次閱讀
    嵌入式實時操作系統——二值<b class='flag-5'>信號量</b>

    如何在Semaphore(信號量)和Mutex(互斥)之間做選擇?

    在單CPU系統中,處理器是一個共享資源。在多個進程之間共享處理器時,處理器的使用由調度程序控制,不存在競爭問題。
    的頭像 發表于 03-05 11:35 ?937次閱讀
    如何在Semaphore(<b class='flag-5'>信號量</b>)和Mutex(<b class='flag-5'>互斥</b>)之間做選擇?

    plc模擬輸出怎么接線 plc模擬輸出是什么信號

    ,通常用于控制和調節外部設備的運行狀態。下面將詳細介紹PLC模擬輸出的接線方法、信號類型、輸出范圍以及其在實際應用中的應用。 接線方法: PLC模擬輸出需要通過模擬
    的頭像 發表于 02-05 14:46 ?5272次閱讀

    信號量實現原理介紹

    除了原子操作,中斷屏蔽,自旋鎖以及自旋鎖的衍生鎖之外,在Linux內核中還存在著一些其他同步互斥的手段。
    的頭像 發表于 01-10 09:07 ?1110次閱讀

    PLC開關信號和模擬信號如何轉換?

    PLC開關信號和模擬信號的轉化問題也是PLC的經典應用問題。要說清楚PLC開關信號和模擬
    發表于 12-17 10:05 ?1643次閱讀
    PLC開關<b class='flag-5'>量</b><b class='flag-5'>信號</b>和模擬<b class='flag-5'>量</b><b class='flag-5'>信號</b>如何轉換?

    FreeRTOS信號量的使用與實例

    在嵌入式系統中,任務管理是一個重要的部分,它涉及到任務之間的通信和同步,信號量,隊列,互斥鎖和事件標志組等概念。本文將以 FreeRTOS 為例,詳細講解這些內容。
    的頭像 發表于 12-12 15:25 ?2399次閱讀