事件组同步(Event Group Sync)

事件组同步(Event Group Sync)

什么是事件组同步 如果有三个任务Task A,Task B,Task C`,它们需要在同一时刻继续执行,那么可以用事件组里来同步它们: Task A设置在事件组中的第一个位 --> 0x01 --> 0001 Task B设置在事件组中的第二个位 --> 0x02 --> 0010 Task C设置

什么是事件组同步

如果有三个任务Task A,Task BTask C`,它们需要在同一时刻继续执行,那么可以用事件组里来同步它们:

  • Task A设置在事件组中的第一个位 --> 0x01 --> 0001
  • Task B设置在事件组中的第二个位 --> 0x02 --> 0010
  • Task C设置在事件组中的第三个位 --> 0x04 --> 0100
    然后,每个任务都会等待事件组中的所有位都被设置:
  • 0x01 | 0x02 | 0x04 --> 0001 | 0010 | 0100 --> 0111,即0x07
    当所有位都被设置后,事件组的值就会变成0x07,此时所有任务都将被唤醒然后继续执行。

20. 事件组同步(Event Group Sync)-20240618181514654.webp

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 );

函数说明:

  1. 原子地设置事件组中的位(标志):
    • 多个任务可以设置一个事件组中的不同位置(标志),这些标志表示任务已经完成了吗,某些工作或者达到了某种状态。
    • 这些位时原子设置的,这意味着设置操作不会被中断,可以确保设置操作的完整性。
  2. 等待事件组中的某些位组合被设置:
    • 每个任务会等待一个特定的位组合被设置,只有当这个组合中的所有位都被设置之后,任务才会继续执行。
    • 这意味着任务在到达同步点之前会被阻塞,直到其他任务也到达了同步点。
  • 这种机制通常用于 多任务同步,即任务点集合。

参数:

  • 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();
}
Comment