訊號量分析
FreeRTOS的訊號量包括二進位制訊號量、計數訊號量、互斥訊號量(以後簡稱互斥量)和遞迴互斥訊號量(以後簡稱遞迴互斥量)。關於它們的區別可以參考《 FreeRTOS系列第19篇---FreeRTOS訊號量》一文。
訊號量API函式實際上都是巨集,它使用現有的佇列機制。這些巨集定義在semphr.h檔案中。如果使用訊號量或者互斥量,需要包含semphr.h標頭檔案。
二進位制訊號量、計數訊號量和互斥量訊號量的建立API函式是獨立的,但是獲取和釋放API函式都是相同的;遞迴互斥訊號量的建立、獲取和釋放API函式都是獨立的。
1.訊號量建立
在《FreeRTOS高階篇5---FreeRTOS佇列分析》中,我們分析了佇列的實現過程,包括佇列建立、入隊和出隊操作。在那篇文章中我們說過,建立佇列API函式實際是呼叫通用佇列建立函式xQueueGenericCreate()來實現的。其實,不但建立佇列實際呼叫通用佇列建立函式,二進位制訊號量、計數訊號量、互斥量和遞迴互斥量也都直接或間接使用這個函式,如表1-1所示。表1-1中紅色字體表示是間接呼叫xQueueGenericCreate()函式。
表1-1:佇列、訊號量和互斥量建立巨集與直接(間接)執行函式
1.1.建立二進位制訊號量
二進位制訊號量建立實際上是直接使用通用佇列建立函式xQueueGenericCreate()。建立二進位制訊號量API介面實際上是一個巨集,定義如下:
- #define xSemaphoreCreateBinary() \
- xQueueGenericCreate( \
- ( UBaseType_t ) 1, \
- semSEMAPHORE_QUEUE_ITEM_LENGTH, \
- NULL, \
-
NULL
- queueQUEUE_TYPE_BINARY_SEMAPHORE\
- )
通過這個巨集定義我們知道建立二進位制訊號量實際上是建立了一個佇列,佇列項有1個,但是佇列項的大小為0(巨集semSEMAPHORE_QUEUE_ITEM_LENGTH定義為0)。
有了佇列建立的知識,我們可以很容易的畫出初始化後的二進位制訊號量記憶體,如圖1-1所示。
圖1-1:初始化後的二進位制訊號量物件記憶體
或許不止一人像我一樣奇怪,建立一個沒有佇列項儲存空間的佇列,訊號量用什麼表示?其實二進位制訊號量的釋放和獲取都是通過操作佇列結構體成員uxMessageWaiting來實現的(圖1-1紅色部分,uxMessageWaiting表示佇列中當前佇列項的個數)。經過初始化後,變數uxMessageWaiting為0,這說明佇列為空,也就是訊號量處於無效狀態。在使用API函式xSemaphoreTake()獲取訊號之前,需要先釋放一個訊號量。後面講到二進位制訊號量釋放和獲取時還會詳細介紹。
1.2.建立計數訊號量
建立計數訊號量間接使用通用佇列建立函式xQueueGenericCreate()。建立計數訊號量API介面同樣是個巨集定義:
[objc] view plain copy print?- #define xSemaphoreCreateCounting(uxMaxCount, uxInitialCount ) \
- xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), (NULL ) )
建立計數訊號量API介面有兩個引數,含義如下:
- uxMaxCount:最大計數值,當訊號到達這個值後,就不再增長了。
- uxInitialCount:建立訊號量時的初始值。
我們來看一下函式xQueueCreateCountingSemaphore()如何實現的:
[objc] view plain copy print?- QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_tuxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue )
- {
- QueueHandle_t xHandle;
- configASSERT( uxMaxCount != 0 );
- configASSERT( uxInitialCount <= uxMaxCount );
- /*呼叫通用佇列建立函式*/
- xHandle =xQueueGenericCreate(
- uxMaxCount,
- queueSEMAPHORE_QUEUE_ITEM_LENGTH,
- NULL,
- pxStaticQueue,
- queueQUEUE_TYPE_COUNTING_SEMAPHORE );
- if( xHandle != NULL )
- {
- ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount;
- }
- configASSERT( xHandle );
- return xHandle;
- }
從程式碼可以看出,建立計數訊號量仍然呼叫通用佇列建立函式xQueueGenericCreate()來建立一個佇列,佇列項的數目由引數uxMaxCount指定,每個佇列項的大小由巨集queueSEMAPHORE_QUEUE_ITEM_LENGTH指出,我們找到這個巨集定義發現,這個巨集被定義為0,也就是說建立的佇列只有佇列資料結構儲存空間而沒有佇列項儲存空間。
如果佇列建立成功,則將佇列結構體成員uxMessageWaiting設定為初始計數訊號量值。初始化後的計數訊號量記憶體如圖3-1所示。
圖1-2:初始化後的計數訊號量物件記憶體
1.3建立互斥量
建立互斥量間接使用通用佇列建立函式xQueueGenericCreate()。建立互斥量API介面同樣是個巨集,定義如下:
[objc] view plain copy print?- #define xSemaphoreCreateMutex() \
- xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, NULL )
其中,巨集queueQUEUE_TYPE_MUTEX用於通用佇列建立函式,表示建立佇列的型別是互斥量,在文章《FreeRTOS高階篇5---FreeRTOS佇列分析》關於通用佇列建立函式引數說明中提到了這個巨集。
我們來看一下函式xQueueCreateMutex()是如何實現的:
[objc] view plain copy print?- #if ( configUSE_MUTEXES == 1 )
- QueueHandle_t xQueueCreateMutex( const uint8_tucQueueType, StaticQueue_t *pxStaticQueue )
- {
- Queue_t *pxNewQueue;
- const UBaseType_tuxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0;
- /* 防止編譯器產生警告資訊 */
- ( void ) ucQueueType;
- /*呼叫通用佇列建立函式*/
- pxNewQueue = ( Queue_t * )xQueueGenericCreate( uxMutexLength, uxMutexSize, NULL, pxStaticQueue, ucQueueType );
- /* 成功分配新的佇列結構體? */
- if( pxNewQueue != NULL )
- {
- /*xQueueGenericCreate()函式會按照通用佇列的方式設定所有佇列結構體成員,但是我們是要建立互斥量.因此需要對一些結構體成員重新賦值. */
- pxNewQueue->pxMutexHolder = NULL;
- pxNewQueue->uxQueueType =queueQUEUE_IS_MUTEX; //NULL
- /* 用於遞迴互斥量建立 */
- pxNewQueue->u.uxRecursiveCallCount = 0;
- /* 使用一個預期狀態啟動訊號量 */
- ( void ) xQueueGenericSend( pxNewQueue, NULL, ( TickType_t ) 0U, queueSEND_TO_BACK);
- }
- return pxNewQueue;
- }
- #endif /* configUSE_MUTEXES */
這個函式是帶條件編譯的,只有將巨集configUSE_MUTEXES定義為1才會編譯這個函式。
函式首先呼叫通用佇列建立函式xQueueGenericCreate()來建立一個佇列,佇列項數目為1,佇列項大小為0,說明建立的佇列只有佇列資料結構儲存空間而沒有佇列項儲存空間。
如果佇列建立成功,通用佇列建立函式還會按照通用佇列的方式 初始化所有佇列結構體成員。但是這裡要建立的是互斥量,所以有一些結構體成員必須重新賦值。在這段程式碼中,可能你會疑惑,佇列結構體成員中,並沒有pxMutexHolder和uxQueueType!其實這兩個識別符號只是巨集定義,是專門為互斥量而定義的,如下所示:
[objc] view plain copy print?- #define pxMutexHolder pcTail
- #define uxQueueType pcHead
- #define queueQUEUE_IS_MUTEX NULL
相關推薦
FreeRTOS(18)---FreeRTOS 訊號量分析
FreeRTOS 訊號量分析 FreeRTOS的訊號量包括二進位制訊號量、計數訊號量、互斥訊號量(以後簡稱互斥量)和遞迴互斥訊號量(以後簡稱遞迴互斥量)。關於它們的區別可以參考《 FreeRTOS系列第19篇—FreeRTOS訊號量》一文。 訊號量API函式實
FreeRTOS高階篇6---FreeRTOS訊號量分析
FreeRTOS的訊號量包括二進位制訊號量、計數訊號量、互斥訊號量(以後簡稱互斥量)和遞迴互斥訊號量(以後簡稱遞迴互斥量)。關於它們的區別可以參考《 FreeRTOS系列第19篇---
訊號量分析
FreeRTOS的訊號量包括二進位制訊號量、計數訊號量、互斥訊號量(以後簡稱互斥量)和遞迴互斥訊號量(以後簡稱遞迴互斥量)。關於它們的區別可以參考《 FreeRTOS系列第19篇---Fr
Dubbo原始碼分析:RPC協議實現-服務端併發控制與Semaphore訊號量
概述 Dubbo支援在服務端通過在service或者method,通過executes引數設定每個方法,允許併發呼叫的最大執行緒數,即在任何時刻,只允許executes個執行緒同時呼叫該方法,超過的則拋異常返回,從而對提供者服務進行併發控制,保護資源。 用法 服務級別 限
Semaphore-訊號量的實現分析
Semaphore Semaphore 訊號量:可以用來控制同時訪問特定資源的執行緒數量;通過協調各個執行緒以保證合理的使用公共資源。 構造 // permits 設定許可證的數量 public Semaphore(int permits) { // 預設非公平 sync =
【本人禿頂程式設計師】Java併發:Semaphore訊號量原始碼分析
←←←←←←←←←←←← 快,點關注! JUC 中 Semaphore 的使用與原理分析,Semaphore 也是 Java 中的一個同步器,與 CountDownLatch 和 CycleBarrier 不同在於它內部的計數器是遞增的,那麼,Semaphore 的內部實現是怎樣的呢?
【4FreeRTOS完整的分析一下程式碼】二值訊號量
1,主要的就是分析下面的程式碼 /* Includes ------------------------------------------------------------------*/ #include "main.h" //包含了三個標頭
原始碼分析:Semaphore之訊號量
## 簡介 Semaphore 又名計數訊號量,從概念上來講,訊號量初始並維護一定數量的許可證,使用之前先要先獲得一個許可,用完之後再釋放一個許可。訊號量通常用於限制執行緒的數量來控制訪問某些資源,從而達到單機限流的目的,比如SpringCloud 中的Zuul 元件用的是 Hystrix 的訊號量(sem
ECMAScript變量分析
即使 自由 字符串 string sof 在外 似的 語言 變量賦值 ECMAScript變量可能包含兩種不同數據類型的值:基本類型值和引用類型值。 基本類型值指的是簡單的數據段,而它包括五種基本數據類型分別是:Undefined、Null、Boolean、Num
[領卓教育]執行緒的同步與互斥機制——訊號量
訊號量的初始化 int sem_init(sem_t *sem, int pshared, unsigned int value); 功能: 初始化訊號量 引數: sem :要是初始化的訊號量 pshared: 訊號量共享的範圍(0: 執行緒間使用 非0:程序間使用) value : 初始
作業系統 自旋鎖+訊號量+互斥量+臨界區+死鎖的區別
自旋鎖(SpinLock) 自旋鎖是專為防止多處理器併發而引入的一種鎖。如果是單核處理器,則自旋鎖定義為空操作,因為簡單的關閉中斷即可實現互斥。 自旋鎖最多隻能被一個執行緒持有,如果一個執行緒試圖請求一個已被爭用(已被另一個執行緒持有)的自旋鎖,那麼等待自旋鎖的執行緒將會反
多執行緒,訊號量的簡單使用 GCD
基本概念 關於iOS開發中,多執行緒基本的概念和基本使用,我在這裡就不在重複說了。但是為了照顧到有的同學可能還不是對基本的概念不熟悉,可以參考一下這篇文章併發其實很簡單 說說訊號量,併發數 如果你有計算機基礎,那麼下面這段話應該很簡單就能理解 訊號量就是一個資源計數器,對訊號
Linux多執行緒程式設計---執行緒間同步(互斥鎖、條件變數、訊號量和讀寫鎖)
本篇博文轉自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了多種方式來處理執行緒同步,最常用的是互斥鎖、條件變數、訊號量和讀寫鎖。 下面是思維導
【Nginx】訊號量
TERM, INT Quick shutdown QUIT Graceful shutdown 優雅的關閉程序,即等請求結束後再關閉 KILL
linux 多執行緒之訊號量 sem_init
1. 什麼是訊號量 linux sem 訊號量是一種特殊的變數,訪問具有原子性, 用於解決程序或執行緒間共享資源引發的同步問題。 使用者態程序對 sem 訊號量可以有以下兩種操作: 等待訊號量 當訊號量值為 0 時,程式等待;當訊號量值大於 0 時,訊號量減 1,程式
Linux基礎(四)——訊號量與PV操作
在計算機作業系統中,PV操作是程序管理中的難點。1、基本含義 什麼是訊號量?訊號量(semaphore)的資料結構為一個值和一個指標,指標指向等待該訊號量的下一個程序。訊號量的值與相應資源的使用情況有關。當它的值大於0時,表示當前可用資源的
PYTHON——多執行緒:訊號量(Semaphore)
訊號量也是一把鎖,用來控制執行緒併發數的。 BoundedSemaphore或Semaphore管理一個內建的計數 器,每當呼叫acquire()時-1,呼叫release()時+1。 計數器不能小於0,當計數器為 0時,acquire()將阻塞執行緒至同
【Qt開發】QThread中的互斥、讀寫鎖、訊號量、條件變數
在gemfield的《從pthread到QThread》一文中我們瞭解了執行緒的基本使用,但是有一大部分的內容當時說要放到這片文章裡討論,那就是執行緒的同步問題。關於這個問題,gemfield在《從進 程到執行緒》中有一個比喻,有必要重新放在下面溫習下: ***************
【OS】訊號量機制
儲存一下自己看,侵刪。 原文地址:http://blog.csdn.net/speedme/article/details/17597373 上篇部落格中(程序同步之臨界區域問題及Peterson演算法),我們對臨界區,臨界資源,鎖機制詳細解讀了下,留下了一個問題,就是鎖機制只能判斷臨界資源是否被佔用,所
【Windows原理】執行緒同步-訊號量
#include "stdafx.h" #include <windows.h> int g_num = 0; HANDLE g_hSemaphore = nullptr; DWORD WINAPI ThreadProc(LPVOID lpParam) { for