在实时嵌入式系统中,信号量、事件组和任务通知是常用的同步与通信机制,它们在不同场景下有着各自的优势与适用性。本文将深入探讨这三种机制的异同,分析它们的特点及何时可以相互替代,并通过详细的代码演示展示它们的具体应用。
1. 信号量(Semaphore)
1.1 特点
- 计数型: 信号量是一种计数型的同步机制,允许多个任务同时访问共享资源。
- 阻塞与唤醒: 当信号量计数为0时,任务会被阻塞,直到信号量计数大于0时才能继续执行。
- 资源争用: 信号量可以用于处理资源的争用问题,通过控制资源的访问权限。
1.2 代码演示
以下是使用FreeRTOS中的信号量实现任务同步的简单代码演示:
#include <FreeRTOS.h>
#include <task.h>
#include <semphr.h>
SemaphoreHandle_t xSemaphore;
void TaskA(void *pvParameters) {
while (1) {
// 等待获取信号量
if (xSemaphoreTake(xSemaphore, portMAX_DELAY)) {
// 访问共享资源
// ...
// 释放信号量
xSemaphoreGive(xSemaphore);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void TaskB(void *pvParameters) {
while (1) {
// 等待获取信号量
if (xSemaphoreTake(xSemaphore, portMAX_DELAY)) {
// 访问共享资源
// ...
// 释放信号量
xSemaphoreGive(xSemaphore);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
int main() {
// 创建信号量
xSemaphore = xSemaphoreCreateBinary();
// 创建任务
xTaskCreate(TaskA, "TaskA", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(TaskB, "TaskB", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
// 启动调度器
vTaskStartScheduler();
return 0;
}
2. 事件组(Event Group)
2.1 特点
- 位掩码: 事件组使用位掩码的方式表示多个事件状态,每个位代表一个事件。
- 等待与触发: 任务可以等待特定的位或多个位的状态,也可以触发(设置)特定的位。
- 轻量级: 事件组相对轻量级,适用于对事件状态敏感的场景。
2.2 代码演示
以下是使用FreeRTOS中的事件组实现任务同步的简单代码演示:
#include <FreeRTOS.h>
#include <task.h>
#include <event_groups.h>
EventGroupHandle_t xEventGroup;
// 定义事件位
#define EVENT_BIT_A (1 << 0)
#define EVENT_BIT_B (1 << 1)
void TaskA(void *pvParameters) {
while (1) {
// 等待事件位A
EventBits_t bits = xEventGroupWaitBits(xEventGroup, EVENT_BIT_A, pdTRUE, pdFALSE, portMAX_DELAY);
// 访问共享资源
// ...
// 释放事件位A
xEventGroupClearBits(xEventGroup, EVENT_BIT_A);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void TaskB(void *pvParameters) {
while (1) {
// 触发事件位A
xEventGroupSetBits(xEventGroup, EVENT_BIT_A);
// 访问共享资源
// ...
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
int main() {
// 创建事件组
xEventGroup = xEventGroupCreate();
// 创建任务
xTaskCreate(TaskA, "TaskA", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(TaskB, "TaskB", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
// 启动调度器
vTaskStartScheduler();
return 0;
}
3. 任务通知(Task Notification)
3.1 特点
- 单一事件: 任务通知用于单一事件的通知,任务可以等待通知的到来。
- 无阻塞等待: 任务通知支持无阻塞等待,任务可以轮询等待通知。
- 低延迟: 任务通知的实现相对轻量,适用于对低延迟要求较高的场景。
3.2 代码演示
以下是使用FreeRTOS中的任务通知实现任务同步的简单代码演示:
#include <FreeRTOS.h>
#include <task.h>
TaskHandle_t xTaskA;
TaskHandle_t xTaskB;
void TaskA(void *pvParameters) {
while (1) {
// 等待任务通知
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// 访问共享资源
// ...
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void TaskB(void *pvParameters) {
while (1) {
// 发送任务通知给TaskA
xTaskNotifyGive(xTaskA);
// 访问共享资源
// ...
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
int main() {
// 创建任务
xTaskCreate(TaskA, "TaskA", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskA);
xTaskCreate(TaskB, "TaskB", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskB);
// 启动调度器
vTaskStartScheduler();
return 0;
}
4. 异同及何时可以替代
4.1 异同点
- 信号量: 适用于资源争用场景,支持计数,可以用于多任务的同步与互斥。
- 事件组: 适用于多事件状态管理场景,轻量级,但不支持计数。
- 任务通知: 适用于单一事件通知场景,轻量级,低延迟。
4.2 替代应用分析
- 使用信号量替代事件组: 当需要对资源进行计数控制,或者需要实现互斥操作时,可以考虑使用信号量替代事件组。
- 使用事件组替代信号量: 当需要对多个事件状态进行管理,并且不需要计数功能时,可以考虑使用事件组替代信号量。
- 使用任务通知替代信号量或事件组: 当只有单一事件的通知需求,并且对低延迟有较高要求时,可以考虑使用任务通知替代信号量或事件组。
5. 总结
信号量、事件组和任务通知是实时嵌入式系统中常用的同步与通信机制,它们在不同场景下具有各自的优势。选择合适的机制取决于具体的应用需求,通过深入了解它们的特点及使用方式,开发者可以更灵活地应对不同的任务同步与通信问题。希望本文的详细代码演示和异同分析能够帮助读者更好地理解和应用这三种机制
标签:异同,通知,void,超细,信号量,任务,事件,include From: https://blog.51cto.com/u_16192077/8850249