嵌入式开发必掌握:任务同步与通信机制实战(信号量+队列+事件组+任务通知)
标签:嵌入式开发、RTOS、FreeRTOS、任务同步、信号量、队列、事件组、任务通知、互斥量、生产者消费者
前言
摘要:任务同步与通信是RTOS多任务编程的核心技术。本文从信号量机制、队列通信、事件组同步、任务通知到生产者-消费者模型实战,提供全套可直接量产的代码示例,同时总结二值信号量vs互斥量、队列vs任务通知、优先级翻转、死锁预防等踩坑经验,帮助开发者掌握高效可靠的任务同步编程技术。
多任务系统中,任务间的同步与通信是保证系统正确运行的关键。FreeRTOS提供了丰富的同步机制:信号量、互斥量、队列、事件组、任务通知等,每种机制都有其适用场景和使用技巧。
文章主要内容:
- 信号量机制详解
- 互斥量与优先级继承
- 队列通信机制
- 事件组同步
- 任务通知机制
- 生产者-消费者模型
- 死锁预防策略
一、信号量机制详解
1.1 信号量基本概念
信号量(Semaphore):用于任务同步和资源管理的计数器机制。
1.2 二值信号量
#include "FreeRTOS.h"
#include "semphr.h"
SemaphoreHandle_t binary_sem;
void Binary_Semaphore_Init(void)
{
binary_sem = xSemaphoreCreateBinary();
if(binary_sem == NULL)
{
printf("Binary Semaphore Create Failed\r\n");
}
}
void ISR_Handler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(binary_sem, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void Task_WaitEvent(void *pvParameters)
{
while(1)
{
if(xSemaphoreTake(binary_sem, portMAX_DELAY) == pdTRUE)
{
printf("Event Received\r\n");
ProcessEvent();
}
}
}
void Task_TriggerEvent(void *pvParameters)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
xSemaphoreGive(binary_sem);
printf("Event Triggered\r\n");
}
}
1.3 计数信号量
SemaphoreHandle_t counting_sem;
void Counting_Semaphore_Init(void)
{
counting_sem = xSemaphoreCreateCounting(5, 0);
if(counting_sem == NULL)
{
printf("Counting Semaphore Create Failed\r\n");
}
}
void Resource_Producer(void *pvParameters)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(500));
if(xSemaphoreGive(counting_sem) == pdTRUE)
{
UBaseType_t count = uxSemaphoreGetCount(counting_sem);
printf("Resource Produced, Count: %d\r\n", count);
}
else
{
printf("Resource Pool Full\r\n");
}
}
}
void Resource_Consumer(void *pvParameters)
{
while(1)
{
if(xSemaphoreTake(counting_sem, pdMS_TO_TICKS(2000)) == pdTRUE)
{
UBaseType_t count = uxSemaphoreGetCount(counting_sem);
printf("Resource Consumed, Count: %d\r\n", count);
}
else
{
printf("Resource Timeout\r\n");
}
}
}
1.4 信号量应用场景
二、互斥量与优先级继承
2.1 互斥量基本概念
互斥量(Mutex):具有优先级继承机制的特殊二值信号量,用于互斥访问共享资源。
SemaphoreHandle_t mutex;
void Mutex_Init(void)
{
mutex = xSemaphoreCreateMutex();
if(mutex == NULL)
{
printf("Mutex Create Failed\r\n");
}
}
void Task_AccessResource(void *pvParameters)
{
while(1)
{
if(xSemaphoreTake(mutex, pdMS_TO_TICKS(100)) == pdTRUE)
{
printf("Resource Acquired\r\n");
AccessSharedResource();
xSemaphoreGive(mutex);
printf("Resource Released\r\n");
}
else
{
printf("Resource Acquire Timeout\r\n");
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}
2.2 优先级翻转问题
2.3 优先级继承机制
#define configUSE_MUTEXES 1
SemaphoreHandle_t mutex_with_inheritance;
void Mutex_PriorityInheritance_Init(void)
{
mutex_with_inheritance = xSemaphoreCreateMutex();
if(mutex_with_inheritance == NULL)
{
printf("Mutex Create Failed\r\n");
}
}
void Task_LowPriority(void *pvParameters)
{
while(1)
{
if(xSemaphoreTake(mutex_with_inheritance, portMAX_DELAY) == pdTRUE)
{
printf("Low Priority Task: Acquired Mutex\r\n");
printf("Priority Inherited to: %d\r\n",
uxTaskPriorityGet(NULL));
vTaskDelay(pdMS_TO_TICKS(100));
xSemaphoreGive(mutex_with_inheritance);
printf("Low Priority Task: Released Mutex\r\n");
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void Task_HighPriority(void *pvParameters)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(10));
if(xSemaphoreTake(mutex_with_inheritance, portMAX_DELAY) == pdTRUE)
{
printf("High Priority Task: Acquired Mutex\r\n");
vTaskDelay(pdMS_TO_TICKS(50));
xSemaphoreGive(mutex_with_inheritance);
printf("High Priority Task: Released Mutex\r\n");
}
}
}
2.4 递归互斥量
SemaphoreHandle_t recursive_mutex;
void Recursive_Mutex_Init(void)
{
recursive_mutex = xSemaphoreCreateRecursiveMutex();
if(recursive_mutex == NULL)
{
printf("Recursive Mutex Create Failed\r\n");
}
}
void Function_Level2(void)
{
if(xSemaphoreTakeRecursive(recursive_mutex, portMAX_DELAY) == pdTRUE)
{
printf("Level 2: Acquired\r\n");
xSemaphoreGiveRecursive(recursive_mutex);
printf("Level 2: Released\r\n");
}
}
void Function_Level1(void)
{
if(xSemaphoreTakeRecursive(recursive_mutex, portMAX_DELAY) == pdTRUE)
{
printf("Level 1: Acquired\r\n");
Function_Level2();
xSemaphoreGiveRecursive(recursive_mutex);
printf("Level 1: Released\r\n");
}
}
三、队列通信机制
3.1 队列基本概念
队列(Queue):用于任务间传递数据的FIFO缓冲区。
3.2 队列创建与使用
#include "FreeRTOS.h"
#include "queue.h"
QueueHandle_t data_queue;
typedef struct
{
uint8_t id;
uint32_t timestamp;
float value;
} SensorData_t;
void Queue_Init(void)
{
data_queue = xQueueCreate(10, sizeof(SensorData_t));
if(data_queue == NULL)
{
printf("Queue Create Failed\r\n");
}
}
void Producer_Task(void *pvParameters)
{
SensorData_t data;
uint32_t count = 0;
while(1)
{
data.id = 1;
data.timestamp = xTaskGetTickCount();
data.value = (float)count * 0.1f;
if(xQueueSend(data_queue, &data, pdMS_TO_TICKS(100)) == pdPASS)
{
printf("Sent: ID=%d, Value=%.2f\r\n", data.id, data.value);
count++;
}
else
{
printf("Queue Full\r\n");
}
vTaskDelay(pdMS_TO_TICKS(200));
}
}
void Consumer_Task(void *pvParameters)
{
SensorData_t data;
while(1)
{
if(xQueueReceive(data_queue, &data, pdMS_TO_TICKS(1000)) == pdPASS)
{
printf("Received: ID=%d, Time=%lu, Value=%.2f\r\n",
data.id, data.timestamp, data.value);
}
else
{
printf("Queue Empty\r\n");
}
}
}
3.3 队列集
#include "queue.h"
QueueHandle_t queue1;
QueueHandle_t queue2;
QueueSetHandle_t queue_set;
void QueueSet_Init(void)
{
queue1 = xQueueCreate(5, sizeof(uint32_t));
queue2 = xQueueCreate(5, sizeof(uint32_t));
queue_set = xQueueCreateSet(5 + 5);
xQueueAddToSet(queue1, queue_set);
xQueueAddToSet(queue2, queue_set);
}
void MultiQueue_Consumer(void *pvParameters)
{
QueueSetMemberHandle_t active_member;
uint32_t data;
while(1)
{
active_member = xQueueSelectFromSet(queue_set, portMAX_DELAY);
if(active_member == queue1)
{
xQueueReceive(queue1, &data, 0);
printf("Queue1: %lu\r\n", data);
}
else if(active_member == queue2)
{
xQueueReceive(queue2, &data, 0);
printf("Queue2: %lu\r\n", data);
}
}
}
3.4 队列应用场景
typedef struct
{
uint8_t cmd;
uint8_t param[16];
uint8_t param_len;
} Command_t;
QueueHandle_t cmd_queue;
void Command_Processor_Task(void *pvParameters)
{
Command_t cmd;
while(1)
{
if(xQueueReceive(cmd_queue, &cmd, portMAX_DELAY) == pdPASS)
{
switch(cmd.cmd)
{
case 0x01:
ProcessCommand1(cmd.param, cmd.param_len);
break;
case 0x02:
ProcessCommand2(cmd.param, cmd.param_len);
break;
default:
printf("Unknown Command: 0x%02X\r\n", cmd.cmd);
break;
}
}
}
}
void UART_RX_Task(void *pvParameters)
{
Command_t cmd;
while(1)
{
if(ReceiveCommand(&cmd))
{
xQueueSend(cmd_queue, &cmd, portMAX_DELAY);
}
}
}
四、事件组同步
4.1 事件组基本概念
事件组(Event Group):用于多事件同步的位标志集合。
4.2 事件组创建与使用
#include "event_groups.h"
EventGroupHandle_t event_group;
#define EVENT_BIT_0 (1 << 0)
#define EVENT_BIT_1 (1 << 1)
#define EVENT_BIT_2 (1 << 2)
#define EVENT_BIT_3 (1 << 3)
void EventGroup_Init(void)
{
event_group = xEventGroupCreate();
if(event_group == NULL)
{
printf("Event Group Create Failed\r\n");
}
}
void EventProducer_Task(void *pvParameters)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
xEventGroupSetBits(event_group, EVENT_BIT_0);
printf("Set Event Bit 0\r\n");
vTaskDelay(pdMS_TO_TICKS(500));
xEventGroupSetBits(event_group, EVENT_BIT_1);
printf("Set Event Bit 1\r\n");
}
}
void EventConsumer_Task(void *pvParameters)
{
EventBits_t event_bits;
while(1)
{
event_bits = xEventGroupWaitBits(
event_group,
EVENT_BIT_0 | EVENT_BIT_1,
pdTRUE,
pdTRUE,
portMAX_DELAY);
if((event_bits & EVENT_BIT_0) && (event_bits & EVENT_BIT_1))
{
printf("Both Events Received\r\n");
}
}
}
4.3 多事件同步场景
#define EVENT_SENSOR_READY (1 << 0)
#define EVENT_NETWORK_READY (1 << 1)
#define EVENT_USER_READY (1 << 2)
void Sensor_Task(void *pvParameters)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(100));
ReadSensorData();
xEventGroupSetBits(event_group, EVENT_SENSOR_READY);
}
}
void Network_Task(void *pvParameters)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(200));
if(NetworkConnect())
{
xEventGroupSetBits(event_group, EVENT_NETWORK_READY);
}
}
}
void Main_Task(void *pvParameters)
{
EventBits_t event_bits;
while(1)
{
event_bits = xEventGroupWaitBits(
event_group,
EVENT_SENSOR_READY | EVENT_NETWORK_READY,
pdTRUE,
pdTRUE,
portMAX_DELAY);
printf("All Systems Ready\r\n");
ProcessData();
}
}
4.4 中断中设置事件
void EXTI0_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
xEventGroupSetBitsFromISR(event_group,
EVENT_BIT_0,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
五、任务通知机制
5.1 任务通知基本概念
任务通知(Task Notification):直接向任务发送32位通知值,比队列更轻量高效。
5.2 任务通知使用
TaskHandle_t task_handle;
void Task_WaitNotification(void *pvParameters)
{
uint32_t notification_value;
while(1)
{
notification_value = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
printf("Notification Received: %lu\r\n", notification_value);
}
}
void Task_SendNotification(void *pvParameters)
{
uint32_t count = 0;
while(1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
xTaskNotify(task_handle, count, eIncrement);
count++;
}
}
void ISR_SendNotification(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(task_handle, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
5.3 通知值操作
typedef enum
{
eNoAction = 0,
eSetBits,
eIncrement,
eSetValueWithOverwrite,
eSetValueWithoutOverwrite
} eNotifyAction;
void Task_NotificationExample(void *pvParameters)
{
uint32_t notification_value;
BaseType_t ret;
while(1)
{
ret = xTaskNotifyWait(0x00, 0xFFFFFFFF, ¬ification_value, portMAX_DELAY);
if(ret == pdPASS)
{
if(notification_value & 0x01)
{
printf("Event 1\r\n");
}
if(notification_value & 0x02)
{
printf("Event 2\r\n");
}
if(notification_value & 0x04)
{
printf("Event 3\r\n");
}
}
}
}
void SetNotificationBits(void)
{
xTaskNotify(task_handle, 0x01, eSetBits);
}
void SetNotificationValue(void)
{
xTaskNotify(task_handle, 100, eSetValueWithOverwrite);
}
void IncrementNotification(void)
{
xTaskNotify(task_handle, 0, eIncrement);
}
5.4 任务通知vs队列
| 特性 | 任务通知 | 队列 |
|---|---|---|
| 创建 | 无需创建 | 需要创建 |
| 内存 | 每个任务自带 | 需要分配内存 |
| 速度 | 快(直接操作) | 较慢(拷贝数据) |
| 数据量 | 32位值 | 任意大小 |
| 接收者 | 单个任务 | 多个任务 |
| 适用场景 | 简单通知 | 复杂数据传递 |
六、生产者-消费者模型
6.1 使用队列实现
#define BUFFER_SIZE 10
typedef struct
{
uint32_t data[BUFFER_SIZE];
uint8_t count;
} DataBuffer_t;
QueueHandle_t data_queue;
SemaphoreHandle_t mutex;
void ProducerConsumer_Init(void)
{
data_queue = xQueueCreate(BUFFER_SIZE, sizeof(uint32_t));
mutex = xSemaphoreCreateMutex();
}
void Producer_Task(void *pvParameters)
{
uint32_t data = 0;
while(1)
{
data++;
if(xQueueSend(data_queue, &data, pdMS_TO_TICKS(100)) == pdPASS)
{
printf("Produced: %lu\r\n", data);
}
else
{
printf("Buffer Full\r\n");
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void Consumer_Task(void *pvParameters)
{
uint32_t data;
while(1)
{
if(xQueueReceive(data_queue, &data, pdMS_TO_TICKS(1000)) == pdPASS)
{
printf("Consumed: %lu\r\n", data);
ProcessData(data);
}
else
{
printf("Buffer Empty\r\n");
}
}
}
6.2 使用计数信号量实现
#define BUFFER_SIZE 10
uint32_t shared_buffer[BUFFER_SIZE];
uint32_t write_index = 0;
uint32_t read_index = 0;
SemaphoreHandle_t empty_sem;
SemaphoreHandle_t full_sem;
SemaphoreHandle_t mutex;
void BoundedBuffer_Init(void)
{
empty_sem = xSemaphoreCreateCounting(BUFFER_SIZE, BUFFER_SIZE);
full_sem = xSemaphoreCreateCounting(BUFFER_SIZE, 0);
mutex = xSemaphoreCreateMutex();
}
void Producer_BoundedBuffer(void *pvParameters)
{
uint32_t data = 0;
while(1)
{
xSemaphoreTake(empty_sem, portMAX_DELAY);
xSemaphoreTake(mutex, portMAX_DELAY);
shared_buffer[write_index] = data++;
write_index = (write_index + 1) % BUFFER_SIZE;
printf("Produced: %lu\r\n", data);
xSemaphoreGive(mutex);
xSemaphoreGive(full_sem);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void Consumer_BoundedBuffer(void *pvParameters)
{
uint32_t data;
while(1)
{
xSemaphoreTake(full_sem, portMAX_DELAY);
xSemaphoreTake(mutex, portMAX_DELAY);
data = shared_buffer[read_index];
read_index = (read_index + 1) % BUFFER_SIZE;
printf("Consumed: %lu\r\n", data);
xSemaphoreGive(mutex);
xSemaphoreGive(empty_sem);
ProcessData(data);
}
}
七、死锁预防策略
7.1 死锁产生条件
7.2 死锁示例
SemaphoreHandle_t mutex_a;
SemaphoreHandle_t mutex_b;
void Task1_Deadlock(void *pvParameters)
{
while(1)
{
xSemaphoreTake(mutex_a, portMAX_DELAY);
printf("Task1: Acquired Mutex A\r\n");
vTaskDelay(pdMS_TO_TICKS(100));
xSemaphoreTake(mutex_b, portMAX_DELAY); // 等待Mutex B
printf("Task1: Acquired Mutex B\r\n");
xSemaphoreGive(mutex_b);
xSemaphoreGive(mutex_a);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void Task2_Deadlock(void *pvParameters)
{
while(1)
{
xSemaphoreTake(mutex_b, portMAX_DELAY);
printf("Task2: Acquired Mutex B\r\n");
vTaskDelay(pdMS_TO_TICKS(100));
xSemaphoreTake(mutex_a, portMAX_DELAY); // 等待Mutex A
printf("Task2: Acquired Mutex A\r\n");
xSemaphoreGive(mutex_a);
xSemaphoreGive(mutex_b);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
7.3 死锁预防方法
方法1:按顺序获取锁
void Task1_NoDeadlock(void *pvParameters)
{
while(1)
{
xSemaphoreTake(mutex_a, portMAX_DELAY);
printf("Task1: Acquired Mutex A\r\n");
vTaskDelay(pdMS_TO_TICKS(100));
xSemaphoreTake(mutex_b, portMAX_DELAY);
printf("Task1: Acquired Mutex B\r\n");
xSemaphoreGive(mutex_b);
xSemaphoreGive(mutex_a);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void Task2_NoDeadlock(void *pvParameters)
{
while(1)
{
xSemaphoreTake(mutex_a, portMAX_DELAY); // 先获取Mutex A
printf("Task2: Acquired Mutex A\r\n");
vTaskDelay(pdMS_TO_TICKS(100));
xSemaphoreTake(mutex_b, portMAX_DELAY); // 再获取Mutex B
printf("Task2: Acquired Mutex B\r\n");
xSemaphoreGive(mutex_b);
xSemaphoreGive(mutex_a);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
方法2:使用超时机制
void Task_TimeoutLock(void *pvParameters)
{
while(1)
{
if(xSemaphoreTake(mutex_a, pdMS_TO_TICKS(1000)) == pdTRUE)
{
printf("Acquired Mutex A\r\n");
if(xSemaphoreTake(mutex_b, pdMS_TO_TICKS(1000)) == pdTRUE)
{
printf("Acquired Mutex B\r\n");
xSemaphoreGive(mutex_b);
}
else
{
printf("Mutex B Timeout\r\n");
}
xSemaphoreGive(mutex_a);
}
else
{
printf("Mutex A Timeout\r\n");
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
方法3:避免嵌套锁
void Task_NoNestedLock(void *pvParameters)
{
while(1)
{
xSemaphoreTake(mutex_a, portMAX_DELAY);
ProcessResourceA();
xSemaphoreGive(mutex_a);
xSemaphoreTake(mutex_b, portMAX_DELAY);
ProcessResourceB();
xSemaphoreGive(mutex_b);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
八、任务同步踩坑总结
8.1 常见问题与解决方案
8.2 踩坑经验汇总
坑点1:二值信号量vs互斥量混淆
// ❌ 错误:用二值信号量做互斥访问
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
xSemaphoreGive(sem); // 初始值设为1
// 问题:没有优先级继承,可能优先级翻转
// ✅ 正确:使用互斥量做互斥访问
SemaphoreHandle_t mutex = xSemaphoreCreateMutex();
// 互斥量特点:
// 1. 具有优先级继承机制
// 2. 只能由获取者释放
// 3. 适用于互斥访问
坑点2:中断中调用阻塞函数
// ❌ 错误:在中断中调用阻塞函数
void ISR_Handler(void)
{
xSemaphoreTake(sem, portMAX_DELAY); // 错误!
xQueueSend(queue, &data, portMAX_DELAY); // 错误!
}
// ✅ 正确:使用FromISR函数
void ISR_Handler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(sem, &xHigherPriorityTaskWoken);
xQueueSendFromISR(queue, &data, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
坑点3:队列数据传递错误
// ❌ 错误:传递指针,数据可能被修改
uint32_t data = 100;
xQueueSend(queue, &data, portMAX_DELAY); // 发送指针
data = 200; // 数据被修改,队列中的数据也变了!
// ✅ 正确:队列会拷贝数据,传递值即可
uint32_t data = 100;
xQueueSend(queue, &data, portMAX_DELAY); // 队列内部拷贝
data = 200; // 不影响队列中的数据
// 注意:如果传递大结构体,考虑传递指针,但要确保数据生命周期
坑点4:事件位超过24位
// ❌ 错误:使用超过24位的事件位
#define EVENT_BIT_25 (1 << 25) // 错误!超过24位
// ✅ 正确:只使用0-23位
#define EVENT_BIT_0 (1 << 0)
#define EVENT_BIT_23 (1 << 23)
// FreeRTOS事件组只有24位可用
坑点5:任务通知覆盖
// ❌ 错误:使用eSetValueWithOverwrite,可能丢失通知
xTaskNotify(task_handle, value1, eSetValueWithOverwrite);
xTaskNotify(task_handle, value2, eSetValueWithOverwrite); // value1被覆盖
// ✅ 正确:根据需求选择合适的操作
xTaskNotify(task_handle, value, eIncrement); // 累加
xTaskNotify(task_handle, bits, eSetBits); // 设置位
8.3 同步机制选择指南
| 场景 | 推荐机制 | 原因 |
|---|---|---|
| 中断通知任务 | 二值信号量/任务通知 | 简单高效 |
| 互斥访问资源 | 互斥量 | 优先级继承 |
| 资源计数 | 计数信号量 | 计数功能 |
| 任务间数据传递 | 队列 | 安全可靠 |
| 多事件同步 | 事件组 | 灵活组合 |
| 简单事件通知 | 任务通知 | 轻量高效 |
九、总结与互动
9.1 核心要点总结
- 信号量:理解二值、计数、互斥量的区别和应用场景
- 队列:掌握队列创建、发送、接收,理解数据拷贝机制
- 事件组:使用事件位实现多事件同步
- 任务通知:轻量高效的同步机制,替代简单信号量
- 死锁预防:按顺序获取锁,使用超时机制
9.2 实战经验总结
- 二值信号量用于同步,互斥量用于互斥访问
- 中断中必须使用FromISR函数
- 队列传递数据会拷贝,注意大结构体的效率
- 任务通知比队列快,但只能传递32位值
- 避免死锁:按顺序获取锁,使用超时
投票组件
你对任务同步机制的最大困惑是什么?
- 不知道何时使用信号量、队列、事件组
- 优先级翻转问题不理解,不知道如何解决
- 死锁问题经常遇到,不知道如何预防
- 中断与任务同步配合不好,系统不稳定
- 其他问题(请评论区说明)
欢迎在评论区分享你的任务同步经验和遇到的问题!
互动引导
思考题:
- 如何设计一个多任务系统,实现数据采集、处理、显示的流水线?
- 如何使用信号量解决优先级翻转问题?
- 如何设计一个线程安全的环形缓冲区?
实践建议:
- 先从简单的二值信号量开始,理解任务同步
- 逐步学习队列、事件组等复杂机制
- 实现生产者-消费者模型,理解实际应用
- 尝试解决优先级翻转、死锁等实际问题
文章标签:嵌入式开发、RTOS、FreeRTOS、任务同步、信号量、队列、事件组、任务通知、互斥量、生产者消费者
版权声明:本文为原创文章,转载请注明出处。文章内容基于FreeRTOS平台,适用于各类RTOS开发场景。
技术交流:欢迎评论区留言讨论,分享你的任务同步经验和踩坑故事!
1400

被折叠的 条评论
为什么被折叠?



