FreeRTOS系列第19篇---FreeRTOS信號量

來自:http://blog.csdn.net/zhzht19861011/article/details/50835613


本文介紹信號量的基礎知識,詳細源碼分析見《FreeRTOS高級篇6---FreeRTOS信號量分析》

1.信號量簡介

? ? ? FreeRTOS的信號量包括二進制信號量計數信號量互斥信號量(以后簡稱互斥量)和遞歸互斥信號量(以后簡稱遞歸互斥量)。

? ? ? 我們可以把互斥量和遞歸互斥量看成特殊的信號量。互斥量和信號量在用法上不同:

  • 信號量用于同步,任務間或者任務和中斷間同步;
  • 互斥量用于互鎖,用于保護同時只能有一個任務訪問的資源,為資源上一把鎖。
  • 信號量用于同步時,一般是一個任務(或中斷)給出信號,另一個任務獲取信號;互斥量必須在同一個任務中獲取信號、同一個任務給出信號。
  • 互斥量具有優先級繼承,信號量沒有。
  • 互斥量不能用在中斷服務程序中,信號量可以。
  • 創建互斥量和創建信號量的API函數不同,但是共用獲取和給出信號API函數;

2.二進制信號量

? ? ? 二進制信號量既可以用于互斥功能也可以用于同步功能。

? ? ? 二進制信號量和互斥量非常相似,但是有一些細微差別:互斥量包含一個優先級繼承機制,二進制信號量則沒有這個機制。這使得二進制信號量更好的用于實現同步(任務間或任務和中斷間),互斥量更好的用于實現簡單互斥。本節僅描述用于同步的二進制信號量。

? ? ? 信號量API函數允許指定一個阻塞時間。當任務企圖獲取一個無效信號量時,任務進入阻塞狀態,阻塞時間用來確定任務進入阻塞的最大時間,阻塞時間單位為系統節拍周期時間。如果有多個任務阻塞在同一個信號量上,那么當信號量有效時,具有最高優先級別的任務最先解除阻塞。

? ? ? 可以將二進制信號量看作只有一個項目(item)的隊列,因此這個隊列只能為空或滿(因此稱為二進制)。任務和中斷使用隊列無需關注誰控制隊列---只需要知道隊列是空還是滿。利用這個機制可以在任務和中斷之間同步。

? ? ? 考慮這樣一種情況,一個任務用來維護外設。使用輪詢的方法會浪費CPU資源并且妨礙其它任務執行。更好的做法是任務的大部分時間處于阻塞狀態(允許其它任務執行),直到某些事件發生該任務才執行。可以使用二進制信號量實現這種應用:當任務取信號量時,因為此時尚未發生特定事件,信號量為空,任務會進入阻塞狀態;當外設需要維護時,觸發一個中斷服務例程,該中斷服務僅僅給出信號量(向隊列寫數據)。任務只是取信號,并不需要歸還,中斷服務只是給信號。

? ? ? 任務的優先級可以用于確保外設及時獲得維護。還可以使用隊列來代替二進制信號量。中斷例程可以捕獲與外設事件相關的數據并將它發往任務的隊列。任務發現隊列數據有效時解除阻塞,如果需要,則進行數據處理。第二種方案使得中斷執行盡可能的短,其它處理過程可以在任務中實現。

? ? ? 注:斷程序中決不可使用無“FromISR”結尾的API函數。

? ? ? 注:在大部分應用場合,任務通知都可以代替二進制信號量,并且速度更快、生成的代碼更少。


圖1-1:中斷和任務之間同步---使用信號量

? ? ? 如圖1-1所示,程序開始運行時,信號量無效,因此任務阻塞在這個信號量下。一段時間后,一個中斷發生,在中斷服務程序中使用API函數xSemaphoreGiveFromISR()給出了一個信號,信號量變得有效。當退出中斷服務程序后,執行上下文切換,任務解除阻塞,使用API函數xSemaphoreTake()取走信號量并執行任務。之后信號量變得無效,任務再次進入阻塞。

3.計數信號量

? ? ? 二進制信號量可以被認為是長度為1的隊列,計數信號量則可以被認為長度大于1的隊列。此外,信號量使用者不必關心存儲在隊列中的數據,只需關心隊列是否為空。

? ? ? 通常計數信號量用于下面兩種事件:

  1. 計數事件:在這種場合下,每當事件發生,事件處理程序將給出一個信號(信號量計數值增1),當處理事件時,處理程序會取走信號量(信號量計數值減1)。因此,計數值是事件發生的數量和事件處理的數量差值。在這種情況下,計數信號量在創建時其值為0。
  2. 資源管理:這種用法下,計數值表示有效的資源數目。任務必須先獲取信號量才能獲取資源控制權。當計數值減為零時表示沒有的資源。當任務完成后,它會返還信號量---信號量計數值增加。在這種情況下,信號量創建時,計數值等于最大資源數目。

? ? ? 注:中斷程序中決不可使用無“FromISR”結尾的API函數。

? ? ? 注:在大部分應用場合,任務通知都可以代替計數信號量,并且速度更快、生成的代碼更少。

4.互斥量

? ? ? 互斥量是一個包含優先級繼承機制的二進制信號量。用于實現同步(任務之間或者任務與中斷之間)的話,二進制信號量是更好的選擇,互斥量用于簡單的互鎖。

? ? ? 用于互鎖的互斥量可以充當保護資源的令牌。當一個任務希望訪問某個資源時,它必須先獲取令牌。當任務使用完資源后,必須還回令牌,以便其它任務可以訪問同一資源。

? ? ? 互斥量和信號量使用相同的API函數,因此互斥量也允許指定一個阻塞時間。阻塞時間單位為系統節拍周期時間,數目表示獲取互斥量無效時最多處于阻塞狀態的系統節拍周期個數。

? ? ? 互斥量與二進制信號量最大的不同是:互斥量具有優先級繼承機制。也就是說,如果一個互斥量(令牌)正在被一個低優先級任務使用,此時一個高優先級企圖獲取這個互斥量,高優先級任務會因為得不到互斥量而進入阻塞狀態,正在使用互斥量的低優先級任務會臨時將自己的優先級提升,提升后的優先級與與進入阻塞狀態的高優先級任務相同。這個優先級提升的過程叫做優先級繼承。這個機制用于確保高優先級任務進入阻塞狀態的時間盡可能短,以及將已經出現的“優先級翻轉”影響降低到最小。

? ? ? 在很多場合中,某個硬件資源只有一個,當低優先級任務占用該資源的時候,即便高優先級任務也只能乖乖的等待低優先級任務釋放資源。這里高優先級任務無法運行而低優先級任務可以運行的現象稱為“優先級翻轉”。

? ? ? 為什么優先級繼承能夠降低優先級翻轉的影響呢?舉個例子,現在有任務A、任務B和任務C,三個任務的優先級順序為任務C>任務B>任務A。任務A和任務C都要使用某一個硬件資源,并且當前任務A占有該資源。

? ? ? 先看沒有優先級繼承的情況:任務C也要使用該資源,但是此時任務A正在使用這個資源,因此任務C進入阻塞,此時三個任務的優先級順序沒有發生變化。在任務C進入阻塞之后,某硬件產生了一次中斷,喚醒了一個事件,該事件可以解除任務B的阻塞狀態。在中斷結束后,因為任務B的優先級是大于任務A的,所以任務B搶占任務A的CPU權限。那么任務C的阻塞時間就至少為:中斷處理時間+任務B的運行時間+任務A的運行時間。

? ? ? 再看有優先級繼承的情況:任務C也要使用該資源,但是此時任務A正在使用這個資源,因此任務C進入阻塞,此時由于優先級A會繼承任務C的優先級,三個任務的優先級順序發生了變化,新的優先級順序為:任務C=任務A>任務B。在任務C進入阻塞之后,某硬件產生了一次中斷,喚醒了一個事件,該事件可以解除任務B的阻塞狀態。在中斷結束后,因為任務A的優先級臨時被提高,大于任務B的優先級,所以任務A繼續獲得CPU權限。任務A完成后,處于高優先級的任務C會接管CPU。所以任務C的阻塞時間為:中斷處理時間+任務A的運行時間。看,任務C的阻塞時間變小了,這就是優先級繼承的優勢。

? ? ? 優先級繼承不能解決優先級反轉,只能將這種情況的影響降低到最小。硬實時系統在一開始設計時就要避免優先級反轉發生。


圖4-1 互斥量用于保護資源

? ? ? 如圖4-1所示,互斥量用來保護資源。為了訪問資源,任務必須先獲取互斥量。任務A想獲取資源,首先它使用API函數xSemaphoreTake()獲取信號量,成功獲取到信號量后,任務A就持有了互斥量,可以安全的訪問資源。期間任務B開始執行,它也想訪問資源,任務B也要先獲得信號量,但是信號量此時是無效的,任務B進入阻塞狀態。當任務A執行完成后,使用API函數xSemaphoreGive()釋放信號量。之后任務B解除阻塞,任務B使用API函數xSemaphoreTake()獲取并得到信號量,任務B可以訪問資源。

5.遞歸互斥量

? ? ? 已經獲取遞歸互斥量的任務可以重復獲取該遞歸互斥量。使用xSemaphoreTakeRecursive()?函數成功獲取幾次遞歸互斥量,就要使用xSemaphoreGiveRecursive()函數返還幾次,在此之前遞歸互斥量都處于無效狀態。比如,某個任務成功獲取5次遞歸互斥量,那么在它沒有返還5次該遞歸互斥量之前,這個互斥量對別的任務無效。

? ? ? 遞歸互斥量可以看成帶有優先級繼承機制的信號量,獲取遞歸互斥量的任務在用完后必須返還。

? ? ? 互斥量不可以用在中斷服務程序中,這是因為:

  • 互斥量具有優先級繼承機制,只有在任務中獲取或給出互斥才有意義。
  • 中斷不能因為等待互斥量而阻塞。

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

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

相關文章

mysql語法替換字符串

UPDATE ht_business_task SET url REPLACE ( url, &, & )轉載于:https://www.cnblogs.com/lz20150121/p/5030739.html

POJ1274 The Perfect Stall(二分圖)

題意: 一些奶牛只有在特定的圍欄中才能產奶,要求合理安排使能產奶的奶牛數達到最大。 要點: 二分圖裸題,最近剛學了二分圖,看下面的參考博客,寫的比較好: 參考博客:匈牙利算法 15479…

藍牙HCI剖析(一)

來自:http://blog.csdn.net/xiaoxiaopengbo/article/details/51334257 一.HCI介紹 HCI提供了訪問bluetooth control的統一接口,通俗來講,就是定義了特定的格式來控制藍牙芯片來做相應的動作(比如inquiry,connect,disconnect&#…

c語言題庫2

96. struct name1{ char str; short x; int num; } struct name2{ char str;0 1 2 3 int num; 4 5 6 7 short x; 8 9 10 11 } sizeof(struct name1)? sizeof(struct name2)? 8、12 97. 讀文件file1.txt的內容(例如): 12 34 56 …

ASP.NET狀緩存Cache的應用-提高數據庫讀取速度

ASP.NET狀緩存Cache的應用-提高數據庫讀取速度 原文:ASP.NET狀緩存Cache的應用-提高數據庫讀取速度一、 Cache概述 既然緩存中的數據其實是來自數據庫的,那么緩存中的數據如何和數據庫進行同步呢?一般來說,緩存中應該存放改動不大或者對…

2016年學習Linux決心書(老男孩教育在線課程班第二期)

我經過這4-5個月的學習后,我一定要達到月薪20K,為了達到這個目標我要付出如下10大行動:1.提前預習上課內容2.上課認真聽講,做好上課筆記3.課后認真做總結,完善筆記5.反復做實驗,并寫實驗文檔6.學…

WPF XAML 從零開始認識XAML

來自&#xff1a;http://blog.csdn.net/aoshilang2249/article/details/44158403 剖析最簡單的XMAL代碼: [html] view plaincopy <Window x:Class"MyFirstApplication.MainWindow" xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentati…

c語言題庫3

143. 枚舉元素本身由系統定義了一個表示序號的數值&#xff0c;從0 開始順序定義為0&#xff0c;1&#xff0c;2…。如在weekday中&#xff0c;sun值為0&#xff0c;mon值為1&#xff0c; …,sat值為6。 main(){  enum weekday  {   sun,mon,tue,wed,thu,fri,sat  } a,b…

入門級----測試的執行、環境的搭建、每日構建、測試記錄和跟蹤、回歸測試、測試總結和報告...

測試用例的準備&#xff0c;都是為了執行測試準備的。 測試環境的搭建 &#xff08;1&#xff09;測試數據&#xff1a;有些測試需要使用大批量的數據&#xff0c;例如容量測試、壓力測試等。根據產品的具體測試要求&#xff0c;可能需要在數據庫表插入大量的數據&#xff0c;準…

MFC讀取配置文件GetPrivateProfileString

VC中 3 個主要 寫入/讀取配置文件ini的函數&#xff1a;bool WritePrivateProfileString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTR lpString,LPCTSTR lpFileName);寫入.ini文件&#xff1b;DWORDGetPrivateProfileString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTR lpD…

UESTC 250 windy數 數位dp

題目鏈接 1 #include<bits/stdc.h>2 using namespace std;3 #define mem1(a) memset(a, -1, sizeof(a))4 #define ll long long5 int dp[20][20], digit[20], len;6 ll dfs(int len, int pre, bool fp, bool first) { //first表示前面的數是否全部為0&#xff0c; pr…

c語言面試題大全

C語言面試題大匯總 4. static有什么用途&#xff1f;&#xff08;請至少說明兩種&#xff09; 1.限制變量的作用域(DL:使其只在定義的當前文件中起作用&#xff0c;static是只能由與變量在同一個文件中定義的程序存取的全局變量。也就是說使全局變量成為文件的私有變量&#…

WindowsAPI詳解——GetCurrentDirectory 獲得程序當前目錄

每個Windows程序都有一個自己的當前目錄&#xff0c;默認是程序exe文件所在的目錄。系統在給程序加載動態鏈接庫文件(DLL)時先在程序當前目錄里查找要加載的DLL&#xff0c;如果在此目錄下沒有找到系統便會去Windows目錄下查找。在這兒我們主要將如何獲得程序的當前目錄&#x…

20151210小問題2

1、各瀏覽器下 scrollTop的差異 IE6/7/8&#xff1a; 對于沒有doctype聲明的頁面里可以使用 document.body.scrollTop 來獲取 scrollTop高度 &#xff1b; 對于有doctype聲明的頁面則可以使用 document.documentElement.scrollTop&#xff1b; Safari: safari 比較特別&#x…

限制MySQL Binlog的傳輸速率

最近一臺核心庫備庫完成恢復后打開slave&#xff0c;導致主庫傳送binlog&#xff0c;瞬間占滿網絡&#xff0c;觸發故障。 為了做一些限制&#xff0c; 給mysql在發送binlog的函數(mysql_binlog_send)里每隔一段時間sleep一次&#xff0c; 增加了兩個參數&#xff1a; master_s…

sprintf用法詳解

printf可能是許多程序員在開始學習C語言時接觸到的第二個函數&#xff08;我猜第一個是main&#xff09;&#xff0c;說起來&#xff0c;自然是老朋友了&#xff0c;可是&#xff0c;你對這個老朋友了解多嗎&#xff1f;你對它的那個孿生兄弟sprintf了解多嗎&#xff1f;在將各…

掌握 Ajax,第 2 部分: 使用 JavaScript 和 Ajax 發出異步請求

轉http://www.ibm.com/developerworks/cn/xml/wa-ajaxintro2/ 掌握 Ajax&#xff0c;第 2 部分: 使用 JavaScript 和 Ajax 發出異步請求 在 Web 請求中使用 XMLHttpRequest 多數 Web 應用程序都使用請求/響應模型從服務器上獲得完整的 HTML 頁面。常常是點擊一個按鈕&#xff0…

Provisioning Services 7.8 入門系列教程之十一 通過版本控制自動更新虛擬磁盤

續Provisioning Services 7.8 入門系列教程之十 通過類自動更新虛擬磁盤從前兩的兩種更新方式可以看出&#xff0c;它們有一個共同的特點&#xff0c;即需要產生&#xff08;復制&#xff09;完成的虛擬磁盤副本&#xff0c;然后進行相關的升級操作。這兩種方法在實際生產中&am…

OC面試題

什么是KVC和KVO&#xff1f; 答&#xff1a;KVC(Key-Value-Coding)內部的實現&#xff1a;一個對象在調用setValue的時候&#xff0c; &#xff08;1&#xff09;首先根據方法名找到運行方法的時候所需要的環境參數。 &#xff08;2&#xff09;他會從自己isa指針結合環境參數&…

【算法】QuickSort

快速排序&#xff0c;時間復雜度O(N*logN)&#xff0c;要能熟練掌握&#xff01; 以下主要參考http://blog.csdn.net/morewindows/article/details/6684558&#xff0c; 感謝原博主&#xff01; 該方法的基本思想是&#xff1a; 1&#xff0e;先從數列中取出一個數作為基準數。…