在RTOS的應用開發中,信號量
也是常用到的一種用於多任務之間信息同步、資源互斥訪問的一種手段,經常使用於協調多個任務訪問同一資源的場景。信號量又分爲計數信號量
和互斥信號量
。計數信號量能夠表示總體資源數量,當獲取一個資源後計數信號量減一,釋放一個資源後計數信號量加一,當信號量爲0時即代表資源被所有分配致使沒法再獲取資源,任務能夠掛起等待直到有資源可用。互斥信號量是能夠理解爲只能維護資源數量爲1的二值計數信號量(值爲0或1),可是互斥信號量又不一樣於計數信號量,由於它還具備優先級繼承
的機制(優先級繼承機制是RTOS中爲了不出現優先級翻轉
問題而作的處理方式。簡單來講就是若是低優先級持有互斥信號量那麼高優先級任務想訪問互斥量就會失敗而掛起等待互斥量被釋放,此時反而是低優先級任務在運行,這就出現了優先級翻轉。爲了不該狀況RTOS處理方式是把正在持有互斥量運行的低優先級任務的優先級提升到與等待訪問互斥資源的高優先級任務同等優先級,這就是優先級繼承。等互斥量被釋放後RTOS會將該任務恢復到以前的低優先級)。api
信號量應用有一個很貼切的舉例就是停車場管理。能夠把停車場的全部停車位看做計數信號量初始值,當有車輛進入停車場計數信號量值減一,當有車輛離開計數信號量值加一。當值爲0時說明沒有空車位了,外面車輛沒法再停進來,須要等到有空車位出現(計數信號量非0)。停車場中的每個停車位又能夠用互斥信號量來表示,當有車輛佔據某車位時代表該車輛持有該車位的互斥信號量,其餘車輛沒法再停在該車位(若是有人非要槓說萬一車位大能夠停2個小車那我莫法哈哈哈)。當該車位車輛離開後代表釋放該車位的互斥信號量,此時其餘車輛能夠停入該車位。app
下面列出ThreadX中使用信號量經常使用到的函數函數
描述線程
此服務爲線程間同步建立一個計數信號量。初始信號量計數被指定爲輸入參數指針
參數code
- semaphore_ptr 指向信號量控制塊的指針
- name_ptr 指向信號量名稱的指針
- initial_count 指定此信號量的初始計數。 合法值的範圍是0x00000000至0xFFFFFFFF
返回值對象
- TX_SUCCESS (0x00) 成功建立信號量
- TX_SEMAPHORE_ERROR (0x0C) 無效的信號量指針。指針是 NULL 或者已經建立了信號量
- TX_CALLER_ERROR (0x13) 該服務的調用者無效
UINT tx_semaphore_create( TX_SEMAPHORE *semaphore_ptr, CHAR *name_ptr, ULONG initial_count);
描述繼承
此服務刪除指定的計數信號量,恢復全部掛起的等待信號量的線程,並返回TX_DELETED狀態。資源
在刪除信號量以前,應用程序必須確保完成(或禁用)此信號量的 put_notify 回調。此外,應用程序必須防止再使用已刪除的信號量。開發
參數
- semaphore_ptr 指向先前建立的信號量的指針
返回值
- TX_SUCCESS (0x00) 成功刪除計數信號量
- TX_SEMAPHORE_ERROR (0x0C) 無效的計數信號量指針
- TX_CALLER_ERROR (0x13) 該服務的調用者無效
UINT tx_semaphore_delete(TX_SEMAPHORE *semaphore_ptr);
描述
此服務從指定的計數信號量獲取一個信號量,指定的信號量計數減小一個。
參數
- semaphore_ptr 指向先前建立的計數信號量的指針
- wait_option :TX_NO_WAIT (0x00000000)不等待直接返回獲取結果;TX_WAIT_FOREVER (0xFFFFFFFF)一直掛起等待直到獲取到信號量;0x00000001 ~ 0xFFFFFFFE指定掛起等待多少個心跳節拍。
返回值
- TX_SUCCESS (0x00) 成功獲取信號量
- TX_DELETED (0x01) 線程掛起時刪除了計數信號量
- TX_NO_INSTANCE (0x0D) 服務沒法檢索計數信號量的實例(在指定的等待時間內信號量計數爲零)
- TX_WAIT_ABORTED (0x1A) 被其餘線程或計時器或中斷打斷而致使服務掛起
- TX_SEMAPHORE_ERROR (0x0C) 計數信號量指針無效
- TX_WAIT_ERROR (0x04) 在非線程調用中指定了TX_NO_WAIT之外的等待選項
UINT tx_semaphore_get( TX_SEMAPHORE *semaphore_ptr, ULONG wait_option);
描述
該服務檢索有關指定信號量的信息
參數
參數爲TX_NULL表示不獲取該參數的信息
- semaphore_ptr 指向信號量控制塊的指針
- name 指向信號量名稱的指針的目標指針
- current_value 指向當前信號量計數的目標的指針
- first_suspended 指向這個信號量掛起列表中第一個線程的指針
- suspended_count 指向當前掛起在此信號量上的線程數的指針
- next_semaphore 指向下一個建立的信號量指針的目標指針
返回值
- TX_SUCCESS (0x00) 獲取信息成功
- TX_SEMAPHORE_ERROR (0x0C) 無效的信號量指針
UINT tx_semaphore_info_get( TX_SEMAPHORE *semaphore_ptr, CHAR **name, ULONG *current_value, TX_THREAD **first_suspended, ULONG *suspended_count, TX_SEMAPHORE **next_semaphore);
- 描述
- 該服務將指定的信號量計數加一。
- 若是在信號量爲0xFFFFFFFF時調用此服務,則新的put操做將致使信號量重置爲零。
- 參數
- semaphore_ptr 指向建立的計數信號量控制塊的指針
- 返回值
- TX_SUCCESS (0x00) 成功放置信號量
- TX_SEMAPHORE_ERROR (0x0C) 指向信號量的指針無效
UINT tx_semaphore_put(TX_SEMAPHORE *semaphore_ptr);
描述
該服務將指定的計數信號量增長一個。 若是計數信號量的當前值大於或等於指定的上限,則不會增長信號量,而且將返回TX_CEILING_EXCEEDED錯誤。
參數
- semaphore_ptr 指向先前建立的信號量的指針
- ceiling 信號量所容許的上限值(有效值範圍是1到0xFFFFFFFF)
返回值
- TX_SUCCESS (0x00) 操做成功
- TX_CEILING_EXCEEDED (0x21) Put請求超過上限
- TX_INVALID_CEILING (0x22) 爲上限提供了無效值零
- TX_SEMAPHORE_ERROR (0x0C) 無效的信號量指針
UINT tx_semaphore_ceiling_put( TX_SEMAPHORE *semaphore_ptr, ULONG ceiling);
描述
此服務爲線程間互斥建立互斥體以保護資源。
參數
- mutex_ptr 指向互斥量控制塊的指針
- name_ptr 指向互斥量名稱的指針
- priority_inherit 指定此互斥對象是否支持優先級繼承。 若是此值爲TX_INHERIT,則支持優先級繼承。 若是指定TX_NO_INHERIT,則此互斥鎖不支持優先級繼承。
返回值
- TX_SUCCESS (0x00) 成功建立信號量
- TX_MUTEX_ERROR (0x1C)無效的互斥指針。 指針爲NULL或互斥體已建立
- TX_CALLER_ERROR (0x13) 該服務的調用者無效
- TX_INHERIT_ERROR (0x1F) 無效的優先級繼承參數
UINT tx_mutex_create( TX_MUTEX *mutex_ptr, CHAR *name_ptr, UINT priority_inherit);
描述
該服務將刪除指定的互斥信號量。 恢復全部等待互斥的已暫停線程,並返回TX_DELETED返回狀態。
應用程序應防止使用已刪除的互斥信號量
參數
- mutex_ptr 指向先前建立的互斥體的指針
返回值
- TX_SUCCESS (0x00) 操做成功
- TX_MUTEX_ERROR (0x1C) 無效的互斥體指針
- TX_CALLER_ERROR (0x13) 該服務的調用者無效
UINT tx_mutex_delete(TX_MUTEX *mutex_ptr);
- 描述
- 該服務嘗試獲取指定互斥鎖的獨佔全部權。 若是調用線程已經擁有互斥鎖,則內部計數器將遞增,並返回成功狀態
- 若是互斥鎖由另外一個線程擁有,而且該線程具備更高的優先級,而且在互斥鎖建立時指定了優先級繼承,則優先級較低的線程的優先級將暫時提升到調用線程的優先級。
- 擁有互斥量的低優先級線程的優先級在互斥體全部權期間絕對不能由外部線程修改
- 參數
- mutex_ptr 指向先前建立的互斥體的指針
- wait_option:TX_NO_WAIT (0x00000000)不等待直接返回獲取結果;TX_WAIT_FOREVER (0xFFFFFFFF)一直掛起等待直到獲取到信號量;0x00000001 ~ 0xFFFFFFFE指定掛起等待多少個心跳節拍。
- 返回值
- TX_SUCCESS (0x00) 操做成功
- TX_DELETED (0x01) 線程暫停時互斥體被刪除
- TX_NOT_AVAILABLE (0x1D) 服務沒法在指定的等待時間內得到互斥鎖的全部權
- TX_WAIT_ABORTED (0x1A) 被其餘線程或計時器或中斷打斷而致使服務掛起
- TX_MUTEX_ERROR (0x1C) 無效的互斥體指針
- TX_WAIT_ERROR (0x04) 在非線程調用中指定了TX_NO_WAIT之外的等待選項
- TX_CALLER_ERROR (0x13) 該服務的調用者無效
UINT tx_mutex_get( TX_MUTEX *mutex_ptr, ULONG wait_option);
- 描述
- 此服務將釋放互斥信號量
- 若是在建立互斥對象時選擇了優先級繼承,那麼釋放線程的優先級將恢復到它最初得到互斥對象全部權時的優先級。在擁有互斥對象期間對釋放線程所作的任何其餘優先級更改均可能被撤消。
- 參數
- mutex_ptr 指向先前建立的互斥體的指針
- 返回值
- TX_SUCCESS (0x00) 操做成功
- TX_NOT_OWNED (0x1E) 互斥對象不歸調用者全部
- TX_MUTEX_ERROR (0x1C) 無效的互斥體指針
- TX_CALLER_ERROR (0x13) 該服務的調用者無效
UINT tx_mutex_put(TX_MUTEX *mutex_ptr);
- 該實例用到的硬件資源:一個串口、兩個按鍵、一個LED
- 建立一個計數信號量,指定數量上限爲3,KEY1申請計數信號量,KEY2增長計數信號量
- 建立一個互斥信號量,用於KEY一、KEY2互斥,即兩個按鍵不能同時按下
- 建立2個任務,一個用於KEY1任務,一個用於KEY2任務,
#define DEMO_STACK_SIZE (2 * 1024) #define DEMO_BYTE_POOL_SIZE (32 * 1024) TX_THREAD thread_0; TX_THREAD thread_1; TX_BYTE_POOL byte_pool_0; UCHAR memory_area[DEMO_BYTE_POOL_SIZE]; TX_MUTEX tx_semaphore_mutex; // 互斥信號量 TX_SEMAPHORE tx_semaphore_count; // 計數信號量
void tx_application_define(void *first_unused_memory) { UINT status; CHAR *pointer = TX_NULL; /* 建立互斥信號量 */ status = tx_mutex_create(&tx_semaphore_mutex,"tx_semaphore_mutex",TX_NO_INHERIT); if (TX_SUCCESS != status) { // 建立失敗處理 } /* 建立計數信號量 */ status = tx_semaphore_create(&tx_semaphore_count, "tx_semaphore_count", 3); if (TX_SUCCESS != status) { // 建立失敗處理 } /* Create a byte memory pool from which to allocate the thread stacks. */ tx_byte_pool_create(&byte_pool_0, "byte pool 0", memory_area, DEMO_BYTE_POOL_SIZE); /* Allocate the stack for thread 0. */ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); /* Create the main thread. */ tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, pointer, DEMO_STACK_SIZE, 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); /* Allocate the stack for thread 1. */ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); /* Create threads 1 */ tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, pointer, DEMO_STACK_SIZE, 2, 2, TX_NO_TIME_SLICE, TX_AUTO_START); }
void thread_0_entry(ULONG thread_input) { UINT status, key_flag = 0; CHAR *name; ULONG current_value; TX_THREAD *first_suspended; ULONG suspended_count; TX_SEMAPHORE *next_semaphore; while(1) { if (0 == key_flag) { if (GPIO_PIN_SET == HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)) { key_flag = 1; /*按鍵按下,獲取互斥信號量*/ status = tx_mutex_get(&tx_semaphore_mutex, TX_NO_WAIT); if (TX_SUCCESS == status) { /*獲取計數信號量*/ if (TX_SUCCESS == tx_semaphore_get(&tx_semaphore_count, TX_NO_WAIT)) { HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin); /*獲取計數信號量信息*/ tx_semaphore_info_get(&tx_semaphore_count, &name, ¤t_value, &first_suspended, &suspended_count, &next_semaphore); printf("key1 pressed, current count semaphore is %d\r\n",(int)current_value); } else { printf("key1 failed to get count semaphore\r\n"); } } else { printf("key1 failed to get mutex semaphore\r\n"); } } } else { if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)) { key_flag = 0; /*按鍵鬆開,釋放互斥信號量*/ tx_mutex_put(&tx_semaphore_mutex); } } tx_thread_sleep(20); } }
void thread_1_entry(ULONG thread_input) { UINT status, key_flag = 0; ULONG current_value; while(1) { if (0 == key_flag) { if (GPIO_PIN_SET == HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)) { key_flag = 1; /*按鍵按下,獲取互斥信號量*/ status = tx_mutex_get(&tx_semaphore_mutex, TX_NO_WAIT); if (TX_SUCCESS == status) { /*計數信號量加一,指定上限爲3*/ //tx_semaphore_put(&tx_semaphore_count); tx_semaphore_ceiling_put(&tx_semaphore_count,3); /*獲取計數信號量信息*/ tx_semaphore_info_get(&tx_semaphore_count, TX_NULL, ¤t_value, TX_NULL, TX_NULL, TX_NULL); printf("key2 pressed, current count semaphore is %d\r\n",(int)current_value); } else { printf("key2 failed to get mutex semaphore\r\n"); } } } else { if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)) { key_flag = 0; /*按鍵鬆開,釋放互斥信號量*/ tx_mutex_put(&tx_semaphore_mutex); } } tx_thread_sleep(20); } }
串口打印演示結果以下
[20:51:33.330]收←◆key1 pressed, current count semaphore is 2 [20:51:34.034]收←◆key1 pressed, current count semaphore is 1 [20:51:34.556]收←◆key1 pressed, current count semaphore is 0 [20:51:34.939]收←◆key1 failed to get count semaphore [20:51:35.522]收←◆key1 failed to get count semaphore [20:51:37.004]收←◆key2 pressed, current count semaphore is 1 [20:51:37.488]收←◆key2 pressed, current count semaphore is 2 [20:51:37.851]收←◆key2 pressed, current count semaphore is 3 [20:51:38.234]收←◆key2 pressed, current count semaphore is 3 [20:51:38.556]收←◆key2 pressed, current count semaphore is 3 [20:51:44.925]收←◆key1 pressed, current count semaphore is 2 [20:51:46.579]收←◆key2 failed to get mutex semaphore [20:51:52.102]收←◆key2 pressed, current count semaphore is 3 [20:51:52.987]收←◆key1 failed to get mutex semaphore