什么是事件组同步
如果有三个任务Task A,
Task B,
Task C`,它们需要在同一时刻继续执行,那么可以用事件组里来同步它们:
Task A
设置在事件组中的第一个位 -->0x01
-->0001
Task B
设置在事件组中的第二个位 -->0x02
-->0010
Task C
设置在事件组中的第三个位 -->0x04
-->0100
然后,每个任务都会等待事件组中的所有位都被设置:0x01 | 0x02 | 0x04
-->0001 | 0010 | 0100
-->0111
,即0x07
。
当所有位都被设置后,事件组的值就会变成0x07
,此时所有任务都将被唤醒然后继续执行。
Task 1 运行,设置自己的位,然后把自己阻塞,等待
Task 2 运行,设置自己的位,然后把自己阻塞,等待
Task 3 运行,设置自己的位,所有位都被设置,所有任务同时开始运行。
官方函数文档
6.1 xEventGroupSync()
[[FreeRTOS_Reference_Manual_V10.0.0.pdf#page=316&selection=2,0,4,17|FreeRTOS_Reference_Manual_V10.0.0, page 316]]
xEventGroupSync()
#include "FreeRTOS.h"
#include "event_group.h"
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait );
函数说明:
- 原子地设置事件组中的位(标志):
- 多个任务可以设置一个事件组中的不同位置(标志),这些标志表示任务已经完成了吗,某些工作或者达到了某种状态。
- 这些位时原子设置的,这意味着设置操作不会被中断,可以确保设置操作的完整性。
- 等待事件组中的某些位组合被设置:
- 每个任务会等待一个特定的位组合被设置,只有当这个组合中的所有位都被设置之后,任务才会继续执行。
- 这意味着任务在到达同步点之前会被阻塞,直到其他任务也到达了同步点。
- 这种机制通常用于 多任务同步,即任务点集合。
参数:
xEventGroup:
事件组句柄。uxBitsToSet:
设置一个位,等待其他的位被设置。uxBitsToWait:
等待的位。xTicksToWait:
最大等待时长。
返回值:
All value
示例代码
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/event_groups.h"
#include "freertos/semphr.h"
#define TASK_0_BIT (1 << 0)
#define TASK_1_BIT (1 << 1)
#define TASK_2_BIT (1 << 2)
#define ALL_BITS_SYNC (TASK_0_BIT | TASK_1_BIT | TASK_2_BIT)
static EventGroupHandle_t event_handle_sync;
void task_a(void *pvPara)
{
printf("[TASK A]: Set.\n");
vTaskDelay(pdMS_TO_TICKS(1000));
xEventGroupSync(event_handle_sync, TASK_0_BIT, ALL_BITS_SYNC, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(1000));
printf("[TASK A]: Resumed.\n");
vTaskDelete(NULL);
}
void task_b(void *pvPara)
{
printf("[TASK B]: Set.\n");
vTaskDelay(pdMS_TO_TICKS(1000));
xEventGroupSync(event_handle_sync, TASK_1_BIT, ALL_BITS_SYNC, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(1000));
printf("[TASK B]: Resumed.\n");
vTaskDelete(NULL);
}
void task_c(void *pvPara)
{
printf("[TASK C]: set.\n");
vTaskDelay(pdMS_TO_TICKS(1000));
xEventGroupSync(event_handle_sync, TASK_2_BIT, ALL_BITS_SYNC, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(1000));
printf("[TASK C]: Resumed.\n");
vTaskDelete(NULL);
}
void app_main(void)
{
event_handle_sync = xEventGroupCreate();
vTaskSuspendAll();
xTaskCreate(task_a, "Task A", 1024 * 5, NULL, 1, NULL);
xTaskCreate(task_b, "Task B", 1024 * 5, NULL, 1, NULL);
xTaskCreate(task_c, "Task C", 1024 * 5, NULL, 1, NULL);
xTaskResumeAll();
}