在嵌入式系統(tǒng)中,任務(wù)管理是一個(gè)重要的部分,它涉及到任務(wù)之間的通信和同步,信號(hào)量,隊(duì)列,互斥鎖和事件標(biāo)志組等概念。本文將以 FreeRTOS 為例,詳細(xì)講解這些內(nèi)容。
1. 任務(wù)間通信與同步概述
在 FreeRTOS 中,任務(wù)是由一個(gè)或多個(gè)函數(shù)組成的獨(dú)立的執(zhí)行流,它們可以獨(dú)立的運(yùn)行和調(diào)度。任務(wù)之間的通信和同步是任務(wù)管理的核心內(nèi)容之一。任務(wù)間的通信是指一個(gè)任務(wù)向另一個(gè)任務(wù)傳遞信息,而同步則是指多個(gè)任務(wù)按照一定的順序執(zhí)行。FreeRTOS 提供了多種任務(wù)間通信和同步的機(jī)制,包括信號(hào)量,隊(duì)列,互斥鎖和事件標(biāo)志組等。
2. 信號(hào)量的使用與實(shí)例
信號(hào)量(Semaphore)是 FreeRTOS 中一種常用的同步機(jī)制,主要用于任務(wù)間和中斷服務(wù)例程(ISR)間的通信。它們被用來保護(hù)共享資源,使得只有一個(gè)任務(wù)或者中斷服務(wù)例程可以訪問共享資源,避免了資源沖突的問題。
FreeRTOS 中的信號(hào)量主要有兩種類型:計(jì)數(shù)信號(hào)量和二值信號(hào)量。
- 計(jì)數(shù)信號(hào)量(Counting Semaphore):是一種可以持有多個(gè)“計(jì)數(shù)”或者“票”的信號(hào)量。例如,如果你有一些共享資源,每個(gè)資源都需要獨(dú)立的訪問控制,你就可以使用一個(gè)初始計(jì)數(shù)等于資源數(shù)量的計(jì)數(shù)信號(hào)量。當(dāng)一個(gè)任務(wù)需要訪問一個(gè)資源時(shí),它會(huì)嘗試“獲取”一個(gè)信號(hào)量。如果信號(hào)量計(jì)數(shù)大于 0,那么信號(hào)量計(jì)數(shù)減 1,任務(wù)繼續(xù)執(zhí)行。如果計(jì)數(shù)為 0,那么任務(wù)就會(huì)阻塞,直到信號(hào)量計(jì)數(shù)大于 0。當(dāng)任務(wù)不再需要訪問資源時(shí),它應(yīng)該“釋放”信號(hào)量,信號(hào)量計(jì)數(shù)加 1。
- 二值信號(hào)量(Binary Semaphore):是一種只有兩個(gè)值(
0
和1
)的特殊信號(hào)量。它通常被用作任務(wù)之間或者任務(wù)與中斷服務(wù)例程之間的同步機(jī)制。當(dāng)信號(hào)量的值為1
時(shí),任務(wù)可以獲取信號(hào)量并繼續(xù)執(zhí)行。當(dāng)信號(hào)量的值為0
時(shí),任務(wù)嘗試獲取信號(hào)量會(huì)被阻塞,直到信號(hào)量的值變?yōu)?code>1。二值信號(hào)量也可以被用作互斥量(Mutex
),用于保護(hù)共享資源的訪問。
在 FreeRTOS 中,信號(hào)量的操作主要有創(chuàng)建(xSemaphoreCreateBinary
, xSemaphoreCreateCounting
等函數(shù))、獲取(xSemaphoreTake
函數(shù))和釋放(xSemaphoreGive
函數(shù))。在中斷服務(wù)例程中,獲取和釋放信號(hào)量的函數(shù)有所不同,分別為xSemaphoreTakeFromISR
和xSemaphoreGiveFromISR
。
示例
計(jì)數(shù)信號(hào)量
假設(shè)有兩個(gè)任務(wù) TaskA 和 TaskB,TaskA 負(fù)責(zé)發(fā)送數(shù)據(jù),TaskB 負(fù)責(zé)接收數(shù)據(jù)。我們使用計(jì)數(shù)信號(hào)量來實(shí)現(xiàn) TaskA 和 TaskB 之間的同步。
首先,在 FreeRTOS 中創(chuàng)建一個(gè)計(jì)數(shù)信號(hào)量:
SemaphoreHandle_t xSemaphore;
xSemaphore = xSemaphoreCreateCounting(10, 0); // 創(chuàng)建一個(gè)計(jì)數(shù)信號(hào)量,初始計(jì)數(shù)值為0,最大計(jì)數(shù)值為10
接下來,在 TaskA 中發(fā)送數(shù)據(jù)時(shí)獲取計(jì)數(shù)信號(hào)量:
void TaskA(void *pvParameters) {
while (1) {
// 發(fā)送數(shù)據(jù)
...
// 獲取計(jì)數(shù)信號(hào)量,如果計(jì)數(shù)值為0,則任務(wù)被阻塞
xSemaphoreTake(xSemaphore, portMAX_DELAY);
}
}
在 TaskB 中接收數(shù)據(jù)時(shí)釋放計(jì)數(shù)信號(hào)量:
void TaskB(void *pvParameters) {
while (1) {
// 接收數(shù)據(jù)
...
// 釋放計(jì)數(shù)信號(hào)量,增加計(jì)數(shù)值
xSemaphoreGive(xSemaphore);
}
}
在上述代碼中,當(dāng) TaskA 發(fā)送數(shù)據(jù)時(shí),它會(huì)獲取計(jì)數(shù)信號(hào)量,如果計(jì)數(shù)值為 0,則 TaskA 會(huì)被阻塞,直到 TaskB 接收數(shù)據(jù)并釋放計(jì)數(shù)信號(hào)量為止。當(dāng) TaskB 釋放計(jì)數(shù)信號(hào)量后,計(jì)數(shù)值增加,TaskA 可以繼續(xù)執(zhí)行發(fā)送數(shù)據(jù)的操作。
這樣,使用計(jì)數(shù)信號(hào)量可以實(shí)現(xiàn) TaskA 和 TaskB 之間的同步,保證 TaskA 在 TaskB 完成接收數(shù)據(jù)后才進(jìn)行發(fā)送數(shù)據(jù)的操作,避免了數(shù)據(jù)的丟失和沖突。
二值信號(hào)量
二值信號(hào)量(Binary Semaphore)是一種用于任務(wù)間同步和互斥的機(jī)制。它只有兩個(gè)狀態(tài),可以是空閑或者被占用,類似于互斥鎖。
下面是一個(gè)使用二值信號(hào)量的示例:
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
// 創(chuàng)建一個(gè)二值信號(hào)量
SemaphoreHandle_t binarySemaphore;
// 任務(wù)1
void task1(void *pvParameters)
{
while (1)
{
// 等待二值信號(hào)量
xSemaphoreTake(binarySemaphore, portMAX_DELAY);
// 執(zhí)行任務(wù)1的操作
// ...
// 釋放二值信號(hào)量
xSemaphoreGive(binarySemaphore);
// 延時(shí)一段時(shí)間
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// 任務(wù)2
void task2(void *pvParameters)
{
while (1)
{
// 等待二值信號(hào)量
xSemaphoreTake(binarySemaphore, portMAX_DELAY);
// 執(zhí)行任務(wù)2的操作
// ...
// 釋放二值信號(hào)量
xSemaphoreGive(binarySemaphore);
// 延時(shí)一段時(shí)間
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main()
{
// 創(chuàng)建二值信號(hào)量
binarySemaphore = xSemaphoreCreateBinary();
// 創(chuàng)建任務(wù)1
xTaskCreate(task1, "Task 1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
// 創(chuàng)建任務(wù)2
xTaskCreate(task2, "Task 2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
// 啟動(dòng)任務(wù)調(diào)度器
vTaskStartScheduler();
return 0;
}
在上面的示例中,首先創(chuàng)建了一個(gè)二值信號(hào)量binarySemaphore
,然后創(chuàng)建了兩個(gè)任務(wù)task1
和task2
。這兩個(gè)任務(wù)都會(huì)在一個(gè)無限循環(huán)中執(zhí)行,首先等待二值信號(hào)量,然后執(zhí)行自己的操作,最后釋放二值信號(hào)量。
當(dāng)一個(gè)任務(wù)等待二值信號(hào)量時(shí),如果二值信號(hào)量的狀態(tài)是空閑(未被占用),則任務(wù)可以獲取到該信號(hào)量,繼續(xù)執(zhí)行自己的操作。如果二值信號(hào)量的狀態(tài)是被占用(已經(jīng)有任務(wù)獲取到了信號(hào)量),則任務(wù)會(huì)一直等待,直到信號(hào)量被釋放。
需要注意的是,當(dāng)一個(gè)任務(wù)獲取到二值信號(hào)量后,其他任務(wù)將無法獲取到該信號(hào)量,直到該任務(wù)釋放信號(hào)量。這就保證了任務(wù)之間的互斥性。
通過使用二值信號(hào)量,可以實(shí)現(xiàn)任務(wù)間的同步和互斥操作,確保多個(gè)任務(wù)按照特定的順序執(zhí)行或者避免資源的競(jìng)爭(zhēng)。
3. 隊(duì)列的使用與實(shí)例
隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),它允許任務(wù)按照先進(jìn)先出(FIFO)的原則將數(shù)據(jù)項(xiàng)插入隊(duì)列和從隊(duì)列中獲取數(shù)據(jù)項(xiàng)。在 FreeRTOS 中,可以使用 xQueueCreate()函數(shù)來創(chuàng)建一個(gè)隊(duì)列。
示例:
QueueHandle_t xQueue;
void vProducerTask(void pvParameters)
{
int32_t lValueToSend;
BaseType_t xStatus;
lValueToSend = (int32_t) pvParameters;
for(;;)
{
xStatus = xQueueSendToBack(xQueue, &lValueToSend, 0);
if(xStatus != pdPASS)
{
printf("Could not send to the queue.n");
}
}
}
在這個(gè)例子中,vProducerTask 任務(wù)將數(shù)據(jù)項(xiàng)發(fā)送到隊(duì)列的尾部。如果發(fā)送成功,xQueueSendToBack()函數(shù)將返回 pdPASS,否則,將返回一個(gè)錯(cuò)誤代碼。
4. 互斥鎖的使用與實(shí)例
互斥鎖是一種用于保護(hù)共享資源的機(jī)制。當(dāng)一個(gè)任務(wù)需要使用一個(gè)共享資源時(shí),它必須首先獲取互斥鎖。如果互斥鎖已經(jīng)被另一個(gè)任務(wù)獲取,那么這個(gè)任務(wù)就需要等待,直到互斥鎖被釋放。在 FreeRTOS 中,可以使用 xSemaphoreCreateMutex()函數(shù)來創(chuàng)建一個(gè)互斥鎖。
示例:
SemaphoreHandle_t xMutex;
void vTask(void pvParameters)
{
for(;;)
{
if(xSemaphoreTake(xMutex, (TickType_t)10) == pdTRUE)
{
// The mutex was successfully taken, so the shared resource can be accessed.
printf("Task: Mutex taken!n");
// ...
// Access the shared resource.
// ...
// Release the mutex.
xSemaphoreGive(xMutex);
}
else
{
// The mutex could not be taken.
printf("Task: Mutex not taken!n");
}
}
}
在這個(gè)例子中,vTask 任務(wù)嘗試獲取一個(gè)互斥鎖。如果成功,它將訪問一個(gè)共享資源,然后釋放互斥鎖。
5. 事件標(biāo)志組的使用與實(shí)例
事件標(biāo)志組是一種用于表示一組事件發(fā)生狀態(tài)的數(shù)據(jù)結(jié)構(gòu)。每一個(gè)事件都有一個(gè)對(duì)應(yīng)的標(biāo)志,當(dāng)事件發(fā)生時(shí),標(biāo)志被設(shè)置,當(dāng)事件被處理時(shí),標(biāo)志被清除。在 FreeRTOS 中,可以使用 xEventGroupCreate()函數(shù)來創(chuàng)建一個(gè)事件標(biāo)志組。
示例:
EventGroupHandle_t xEventGroup;
void vTask(void pvParameters)
{
EventBits_t uxBits;
for(;;)
{
uxBits = xEventGroupWaitBits(
xEventGroup, // The event group being tested.
BIT_0 | BIT_4, // The bits within the event group to wait for.
pdTRUE, // BIT_0 & BIT_4 should be cleared before returning.
pdFALSE, // Don't wait for both bits, either bit will do.
portMAX_DELAY // Wait a maximum for either bit to be set.
);
if((uxBits & (BIT_0 | BIT_4)) == (BIT_0 | BIT_4))
{
// Both bits were set.
printf("Task: Both bits were set!n");
}
else if((uxBits & BIT_0) != 0)
{
// Bit 0 was set.
printf("Task: Bit 0 was set!n");
}
else if((uxBits & BIT_4) != 0)
{
// Bit 4 was set.
printf("Task: Bit 4 was set!n");
}
else
{
// Neither bit was set.
printf("Task: Neither bit was set!n");
}
}
}
在這個(gè)例子中,vTask 任務(wù)等待事件標(biāo)志組中的任何一個(gè)事件發(fā)生。如果兩個(gè)事件都發(fā)生,它將打印出"Both bits were set!",如果只有一個(gè)事件發(fā)生,它將打印出對(duì)應(yīng)的消息。
6. 信號(hào)量 vs 互斥鎖
信號(hào)量(Semaphore)和互斥鎖(Mutex)都是多任務(wù)環(huán)境下保護(hù)共享資源的一種方法,它們之間存在一些區(qū)別:
- 互斥鎖是一種所有權(quán)的概念,即一個(gè)任務(wù)獲取了互斥鎖后,只有它自己可以釋放這個(gè)互斥鎖,其他任務(wù)不能釋放。而信號(hào)量沒有所有權(quán)的概念,任何任務(wù)都可以釋放信號(hào)量。
- 在 FreeRTOS 中,互斥鎖有優(yōu)先級(jí)反轉(zhuǎn)的解決機(jī)制,當(dāng)一個(gè)低優(yōu)先級(jí)的任務(wù)獲取了互斥鎖,而高優(yōu)先級(jí)的任務(wù)需要這個(gè)互斥鎖時(shí),低優(yōu)先級(jí)的任務(wù)的優(yōu)先級(jí)會(huì)被提升,以減少優(yōu)先級(jí)反轉(zhuǎn)的問題。而信號(hào)量沒有這個(gè)機(jī)制。
- 互斥鎖通常用于保護(hù)共享資源,即在同一時(shí)間只能有一個(gè)任務(wù)訪問某個(gè)資源。信號(hào)量則更多是用于任務(wù)同步,它可以被用來喚醒一個(gè)或多個(gè)等待的任務(wù)。
- 在 FreeRTOS 中,信號(hào)量可以有計(jì)數(shù)的概念,即可以被“給”多次,每次“給”都會(huì)增加一個(gè)計(jì)數(shù),而互斥鎖沒有這個(gè)概念,它只有鎖定和解鎖兩種狀態(tài)。
- 信號(hào)量可以被用作二元信號(hào)量(即只有兩種狀態(tài),
0
和1
,類似互斥鎖),而互斥鎖不能被用作計(jì)數(shù)信號(hào)量。
總結(jié)
在 FreeRTOS 中,任務(wù)間的通信和同步是一個(gè)重要的部分,它涉及到信號(hào)量,隊(duì)列,互斥鎖和事件標(biāo)志組等概念。通過理解和掌握這些概念,可以有效地管理和調(diào)度任務(wù),提高系統(tǒng)的效率和穩(wěn)定性。
FreeRTOS 任務(wù)間通信與同步
在嵌入式系統(tǒng)中,任務(wù)管理是一個(gè)重要的部分,它涉及到任務(wù)之間的通信和同步,信號(hào)量,隊(duì)列,互斥鎖和事件標(biāo)志組等概念。本文將以 FreeRTOS 為例,詳細(xì)講解這些內(nèi)容。
1. 任務(wù)間通信與同步概述
在 FreeRTOS 中,任務(wù)是由一個(gè)或多個(gè)函數(shù)組成的獨(dú)立的執(zhí)行流,它們可以獨(dú)立的運(yùn)行和調(diào)度。任務(wù)之間的通信和同步是任務(wù)管理的核心內(nèi)容之一。任務(wù)間的通信是指一個(gè)任務(wù)向另一個(gè)任務(wù)傳遞信息,而同步則是指多個(gè)任務(wù)按照一定的順序執(zhí)行。FreeRTOS 提供了多種任務(wù)間通信和同步的機(jī)制,包括信號(hào)量,隊(duì)列,互斥鎖和事件標(biāo)志組等。
2. 信號(hào)量的使用與實(shí)例
信號(hào)量(Semaphore)是 FreeRTOS 中一種常用的同步機(jī)制,主要用于任務(wù)間和中斷服務(wù)例程(ISR)間的通信。它們被用來保護(hù)共享資源,使得只有一個(gè)任務(wù)或者中斷服務(wù)例程可以訪問共享資源,避免了資源沖突的問題。
FreeRTOS 中的信號(hào)量主要有兩種類型:計(jì)數(shù)信號(hào)量和二值信號(hào)量。
- 計(jì)數(shù)信號(hào)量(Counting Semaphore):是一種可以持有多個(gè)“計(jì)數(shù)”或者“票”的信號(hào)量。例如,如果你有一些共享資源,每個(gè)資源都需要獨(dú)立的訪問控制,你就可以使用一個(gè)初始計(jì)數(shù)等于資源數(shù)量的計(jì)數(shù)信號(hào)量。當(dāng)一個(gè)任務(wù)需要訪問一個(gè)資源時(shí),它會(huì)嘗試“獲取”一個(gè)信號(hào)量。如果信號(hào)量計(jì)數(shù)大于 0,那么信號(hào)量計(jì)數(shù)減 1,任務(wù)繼續(xù)執(zhí)行。如果計(jì)數(shù)為 0,那么任務(wù)就會(huì)阻塞,直到信號(hào)量計(jì)數(shù)大于 0。當(dāng)任務(wù)不再需要訪問資源時(shí),它應(yīng)該“釋放”信號(hào)量,信號(hào)量計(jì)數(shù)加 1。
- 二值信號(hào)量(Binary Semaphore):是一種只有兩個(gè)值(
0
和1
)的特殊信號(hào)量。它通常被用作任務(wù)之間或者任務(wù)與中斷服務(wù)例程之間的同步機(jī)制。當(dāng)信號(hào)量的值為1
時(shí),任務(wù)可以獲取信號(hào)量并繼續(xù)執(zhí)行。當(dāng)信號(hào)量的值為0
時(shí),任務(wù)嘗試獲取信號(hào)量會(huì)被阻塞,直到信號(hào)量的值變?yōu)?code>1。二值信號(hào)量也可以被用作互斥量(Mutex
),用于保護(hù)共享資源的訪問。
在 FreeRTOS 中,信號(hào)量的操作主要有創(chuàng)建(xSemaphoreCreateBinary
, xSemaphoreCreateCounting
等函數(shù))、獲?。?code>xSemaphoreTake函數(shù))和釋放(xSemaphoreGive
函數(shù))。在中斷服務(wù)例程中,獲取和釋放信號(hào)量的函數(shù)有所不同,分別為xSemaphoreTakeFromISR
和xSemaphoreGiveFromISR
。
示例
計(jì)數(shù)信號(hào)量
假設(shè)有兩個(gè)任務(wù) TaskA 和 TaskB,TaskA 負(fù)責(zé)發(fā)送數(shù)據(jù),TaskB 負(fù)責(zé)接收數(shù)據(jù)。我們使用計(jì)數(shù)信號(hào)量來實(shí)現(xiàn) TaskA 和 TaskB 之間的同步。
首先,在 FreeRTOS 中創(chuàng)建一個(gè)計(jì)數(shù)信號(hào)量:
SemaphoreHandle_t xSemaphore;
xSemaphore = xSemaphoreCreateCounting(10, 0); // 創(chuàng)建一個(gè)計(jì)數(shù)信號(hào)量,初始計(jì)數(shù)值為0,最大計(jì)數(shù)值為10
接下來,在 TaskA 中發(fā)送數(shù)據(jù)時(shí)獲取計(jì)數(shù)信號(hào)量:
void TaskA(void *pvParameters) {
while (1) {
// 發(fā)送數(shù)據(jù)
...
// 獲取計(jì)數(shù)信號(hào)量,如果計(jì)數(shù)值為0,則任務(wù)被阻塞
xSemaphoreTake(xSemaphore, portMAX_DELAY);
}
}
在 TaskB 中接收數(shù)據(jù)時(shí)釋放計(jì)數(shù)信號(hào)量:
void TaskB(void *pvParameters) {
while (1) {
// 接收數(shù)據(jù)
...
// 釋放計(jì)數(shù)信號(hào)量,增加計(jì)數(shù)值
xSemaphoreGive(xSemaphore);
}
}
在上述代碼中,當(dāng) TaskA 發(fā)送數(shù)據(jù)時(shí),它會(huì)獲取計(jì)數(shù)信號(hào)量,如果計(jì)數(shù)值為 0,則 TaskA 會(huì)被阻塞,直到 TaskB 接收數(shù)據(jù)并釋放計(jì)數(shù)信號(hào)量為止。當(dāng) TaskB 釋放計(jì)數(shù)信號(hào)量后,計(jì)數(shù)值增加,TaskA 可以繼續(xù)執(zhí)行發(fā)送數(shù)據(jù)的操作。
這樣,使用計(jì)數(shù)信號(hào)量可以實(shí)現(xiàn) TaskA 和 TaskB 之間的同步,保證 TaskA 在 TaskB 完成接收數(shù)據(jù)后才進(jìn)行發(fā)送數(shù)據(jù)的操作,避免了數(shù)據(jù)的丟失和沖突。
二值信號(hào)量
二值信號(hào)量(Binary Semaphore)是一種用于任務(wù)間同步和互斥的機(jī)制。它只有兩個(gè)狀態(tài),可以是空閑或者被占用,類似于互斥鎖。
下面是一個(gè)使用二值信號(hào)量的示例:
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
// 創(chuàng)建一個(gè)二值信號(hào)量
SemaphoreHandle_t binarySemaphore;
// 任務(wù)1
void task1(void *pvParameters)
{
while (1)
{
// 等待二值信號(hào)量
xSemaphoreTake(binarySemaphore, portMAX_DELAY);
// 執(zhí)行任務(wù)1的操作
// ...
// 釋放二值信號(hào)量
xSemaphoreGive(binarySemaphore);
// 延時(shí)一段時(shí)間
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// 任務(wù)2
void task2(void *pvParameters)
{
while (1)
{
// 等待二值信號(hào)量
xSemaphoreTake(binarySemaphore, portMAX_DELAY);
// 執(zhí)行任務(wù)2的操作
// ...
// 釋放二值信號(hào)量
xSemaphoreGive(binarySemaphore);
// 延時(shí)一段時(shí)間
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main()
{
// 創(chuàng)建二值信號(hào)量
binarySemaphore = xSemaphoreCreateBinary();
// 創(chuàng)建任務(wù)1
xTaskCreate(task1, "Task 1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
// 創(chuàng)建任務(wù)2
xTaskCreate(task2, "Task 2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
// 啟動(dòng)任務(wù)調(diào)度器
vTaskStartScheduler();
return 0;
}
在上面的示例中,首先創(chuàng)建了一個(gè)二值信號(hào)量binarySemaphore
,然后創(chuàng)建了兩個(gè)任務(wù)task1
和task2
。這兩個(gè)任務(wù)都會(huì)在一個(gè)無限循環(huán)中執(zhí)行,首先等待二值信號(hào)量,然后執(zhí)行自己的操作,最后釋放二值信號(hào)量。
當(dāng)一個(gè)任務(wù)等待二值信號(hào)量時(shí),如果二值信號(hào)量的狀態(tài)是空閑(未被占用),則任務(wù)可以獲取到該信號(hào)量,繼續(xù)執(zhí)行自己的操作。如果二值信號(hào)量的狀態(tài)是被占用(已經(jīng)有任務(wù)獲取到了信號(hào)量),則任務(wù)會(huì)一直等待,直到信號(hào)量被釋放。
需要注意的是,當(dāng)一個(gè)任務(wù)獲取到二值信號(hào)量后,其他任務(wù)將無法獲取到該信號(hào)量,直到該任務(wù)釋放信號(hào)量。這就保證了任務(wù)之間的互斥性。
通過使用二值信號(hào)量,可以實(shí)現(xiàn)任務(wù)間的同步和互斥操作,確保多個(gè)任務(wù)按照特定的順序執(zhí)行或者避免資源的競(jìng)爭(zhēng)。
3. 隊(duì)列的使用與實(shí)例
隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),它允許任務(wù)按照先進(jìn)先出(FIFO)的原則將數(shù)據(jù)項(xiàng)插入隊(duì)列和從隊(duì)列中獲取數(shù)據(jù)項(xiàng)。在 FreeRTOS 中,可以使用 xQueueCreate()函數(shù)來創(chuàng)建一個(gè)隊(duì)列。
示例:
QueueHandle_t xQueue;
void vProducerTask(void pvParameters)
{
int32_t lValueToSend;
BaseType_t xStatus;
lValueToSend = (int32_t) pvParameters;
for(;;)
{
xStatus = xQueueSendToBack(xQueue, &lValueToSend, 0);
if(xStatus != pdPASS)
{
printf("Could not send to the queue.n");
}
}
}
在這個(gè)例子中,vProducerTask 任務(wù)將數(shù)據(jù)項(xiàng)發(fā)送到隊(duì)列的尾部。如果發(fā)送成功,xQueueSendToBack()函數(shù)將返回 pdPASS,否則,將返回一個(gè)錯(cuò)誤代碼。
4. 互斥鎖的使用與實(shí)例
互斥鎖是一種用于保護(hù)共享資源的機(jī)制。當(dāng)一個(gè)任務(wù)需要使用一個(gè)共享資源時(shí),它必須首先獲取互斥鎖。如果互斥鎖已經(jīng)被另一個(gè)任務(wù)獲取,那么這個(gè)任務(wù)就需要等待,直到互斥鎖被釋放。在 FreeRTOS 中,可以使用 xSemaphoreCreateMutex()函數(shù)來創(chuàng)建一個(gè)互斥鎖。
示例:
SemaphoreHandle_t xMutex;
void vTask(void pvParameters)
{
for(;;)
{
if(xSemaphoreTake(xMutex, (TickType_t)10) == pdTRUE)
{
// The mutex was successfully taken, so the shared resource can be accessed.
printf("Task: Mutex taken!n");
// ...
// Access the shared resource.
// ...
// Release the mutex.
xSemaphoreGive(xMutex);
}
else
{
// The mutex could not be taken.
printf("Task: Mutex not taken!n");
}
}
}
在這個(gè)例子中,vTask 任務(wù)嘗試獲取一個(gè)互斥鎖。如果成功,它將訪問一個(gè)共享資源,然后釋放互斥鎖。
5. 事件標(biāo)志組的使用與實(shí)例
事件標(biāo)志組是一種用于表示一組事件發(fā)生狀態(tài)的數(shù)據(jù)結(jié)構(gòu)。每一個(gè)事件都有一個(gè)對(duì)應(yīng)的標(biāo)志,當(dāng)事件發(fā)生時(shí),標(biāo)志被設(shè)置,當(dāng)事件被處理時(shí),標(biāo)志被清除。在 FreeRTOS 中,可以使用 xEventGroupCreate()函數(shù)來創(chuàng)建一個(gè)事件標(biāo)志組。
示例:
EventGroupHandle_t xEventGroup;
void vTask(void pvParameters)
{
EventBits_t uxBits;
for(;;)
{
uxBits = xEventGroupWaitBits(
xEventGroup, // The event group being tested.
BIT_0 | BIT_4, // The bits within the event group to wait for.
pdTRUE, // BIT_0 & BIT_4 should be cleared before returning.
pdFALSE, // Don't wait for both bits, either bit will do.
portMAX_DELAY // Wait a maximum for either bit to be set.
);
if((uxBits & (BIT_0 | BIT_4)) == (BIT_0 | BIT_4))
{
// Both bits were set.
printf("Task: Both bits were set!n");
}
else if((uxBits & BIT_0) != 0)
{
// Bit 0 was set.
printf("Task: Bit 0 was set!n");
}
else if((uxBits & BIT_4) != 0)
{
// Bit 4 was set.
printf("Task: Bit 4 was set!n");
}
else
{
// Neither bit was set.
printf("Task: Neither bit was set!n");
}
}
}
在這個(gè)例子中,vTask 任務(wù)等待事件標(biāo)志組中的任何一個(gè)事件發(fā)生。如果兩個(gè)事件都發(fā)生,它將打印出"Both bits were set!",如果只有一個(gè)事件發(fā)生,它將打印出對(duì)應(yīng)的消息。
6. 信號(hào)量 vs 互斥鎖
信號(hào)量(Semaphore)和互斥鎖(Mutex)都是多任務(wù)環(huán)境下保護(hù)共享資源的一種方法,它們之間存在一些區(qū)別:
- 互斥鎖是一種所有權(quán)的概念,即一個(gè)任務(wù)獲取了互斥鎖后,只有它自己可以釋放這個(gè)互斥鎖,其他任務(wù)不能釋放。而信號(hào)量沒有所有權(quán)的概念,任何任務(wù)都可以釋放信號(hào)量。
- 在 FreeRTOS 中,互斥鎖有優(yōu)先級(jí)反轉(zhuǎn)的解決機(jī)制,當(dāng)一個(gè)低優(yōu)先級(jí)的任務(wù)獲取了互斥鎖,而高優(yōu)先級(jí)的任務(wù)需要這個(gè)互斥鎖時(shí),低優(yōu)先級(jí)的任務(wù)的優(yōu)先級(jí)會(huì)被提升,以減少優(yōu)先級(jí)反轉(zhuǎn)的問題。而信號(hào)量沒有這個(gè)機(jī)制。
- 互斥鎖通常用于保護(hù)共享資源,即在同一時(shí)間只能有一個(gè)任務(wù)訪問某個(gè)資源。信號(hào)量則更多是用于任務(wù)同步,它可以被用來喚醒一個(gè)或多個(gè)等待的任務(wù)。
- 在 FreeRTOS 中,信號(hào)量可以有計(jì)數(shù)的概念,即可以被“給”多次,每次“給”都會(huì)增加一個(gè)計(jì)數(shù),而互斥鎖沒有這個(gè)概念,它只有鎖定和解鎖兩種狀態(tài)。
- 信號(hào)量可以被用作二元信號(hào)量(即只有兩種狀態(tài),
0
和1
,類似互斥鎖),而互斥鎖不能被用作計(jì)數(shù)信號(hào)量。
總結(jié)
在 FreeRTOS 中,任務(wù)間的通信和同步是一個(gè)重要的部分,它涉及到信號(hào)量,隊(duì)列,互斥鎖和事件標(biāo)志組等概念。通過理解和掌握這些概念,可以有效地管理和調(diào)度任務(wù),提高系統(tǒng)的效率和穩(wěn)定性。
-
嵌入式系統(tǒng)
+關(guān)注
關(guān)注
40文章
3519瀏覽量
128802 -
中斷
+關(guān)注
關(guān)注
5文章
889瀏覽量
41219 -
FreeRTOS
+關(guān)注
關(guān)注
12文章
483瀏覽量
61721 -
信號(hào)量
+關(guān)注
關(guān)注
0文章
53瀏覽量
8282
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論