RTOS: Uso de grupo de eventos para sincronização de tarefas

FreeRTOS oferece, além dos 2 métodos anteriores para comunicação e sincronização de tarefas, os grupos de eventos (abreviando para G.E.). Um G.E. pode armazenar diversos eventos (flags) e, com isso, podemos deixar uma tarefa em espera (estado bloqueado) até que um ou vários eventos específicos ocorram.

 

O que é e como funciona um grupo de eventos?

 

Antes de entender um grupo de eventos, vamos relembrar o que são eventos (flags ou bandeiras). Flags são variáveis (normalmente binárias) que indicam quando algo ocorreu ou não, como por exemplo:

 

  1. Um sensor ativa uma flag ao término de sua leitura;
  2. Uma interrupção atribuída a um botão ativa uma flag indicando que ele foi pressionado.

 

Sendo assim, nosso embarcado pode ter muitas flags indicando diferentes coisas para que possamos tomar atitudes de acordo com a ocorrência delas.

 

Os G.E são variáveis de 16 ou 32 bits (definido pelo usuário) onde cada bit é uma flag específica indicando que algo ocorreu ou não. Nos nossos exemplos, usaremos os grupos de eventos de 32 bits, sendo 24 bits de uso livre e 8 reservados. Já que cada objeto do grupo de eventos permite manipular até 24 eventos diferentes, dependendo do tamanho do seu projeto, pode-se economizar uma preciosa quantidade de memória RAM, comparado com o uso de semáforos binários ou queues para cada evento.

 

Veja um exemplo das flags em um grupo de eventos na figura 1 abaixo:

 

Exemplo de flags em um grupo de eventos.
Figura 1 - Exemplo de flags em um grupo de eventos.

 

Diferentemente dos semáforos e queues, um grupo de eventos tem algumas características importantes:

 

  1. Podemos acordar as tarefas com combinação de uma ou várias flags diferentes;
  2. Reduz o consumo de memória RAM se comparado quando usado vários semáforos binários ou queues para sincronização;
  3. Todas as tarefas que estão esperando (estado bloqueado) pelas flags, são desbloqueadas, funcionando como uma “mensagem broadcast” e não apenas a de maior prioridade, como acontece com os semáforos e queues. Vamos observar essa importante característica nas figuras 2 e 3.

 

Na figura 2, duas tarefas (T1 e T2) esperam pelo mesmo semáforo binário (ou queue) para executar certa ação. Entretanto, quando a tarefa (Main) libera o semáforo para uso, apenas a tarefa de maior prioridade (T2) obtém o semáforo, causando Starvation na tarefa (T1), já que ela nunca será executada.

 

Tarefas esperando pelo mesmo semáforo.
Figura 2 - Tarefas esperando pelo mesmo semáforo.

 

Na figura 3 abaixo, há a mesma lógica porém com grupo de eventos, que desbloqueia todas tarefas (broadcast) e não apenas a de maior prioridade. Este detalhe é muito importante quando você pretende ter mais de uma tarefa esperando pelo mesmo item.

 

Tarefas esperando pelo mesmo evento.
Figura 3 - Tarefas esperando pelo mesmo evento.

 

 

Como já foi dito, um grupo de eventos é um conjunto de bits onde cada um tem seu significado específico, logo, precisamos entender o básico sobre manipulação de bits na linguagem C e você pode aprender mais vendo este ótimo artigo do Fábio Souza aqui. Vamos testar um G.E. na prática, onde uma tarefa espera por um flag para executar sua rotina.

 

Código do projeto:

 

Testando esse simples código, podemos ver que é praticamente idêntico ao funcionamento dos semáforos e queues, porém, como foi dito anteriormente, podemos manter a tarefa bloqueada por um ou mais eventos e isso é feito através de uma pequena lógica, veja a seguir.

 

Vamos resumir e apenas mostrar a parte onde definimos os eventos e a função que os aguarda.

 

 

Com o 4º parâmetro da função em true, a função irá esperar, durante 1 segundo, até que todos os três eventos fiquem valendo 1. Se qualquer um dos três não ocorrer dentro do tempo limite, a função retornará apenas após o tempo limite.

 

Além disso, temos mais uma possibilidade que é configurar a função para esperar por  qualquer um dos três e não mais todos os três juntos, veja abaixo:

 

 

Com o 4º parâmetro da função em false, a função irá esperar, durante 1 segundo, por qualquer um dos três eventos. Se qualquer um dos três eventos ocorrer, a função retornará, imediatamente.

 

A função sempre retorna o valor atual do grupo de eventos, logo, você precisa aplicar máscaras binárias para descobrir se o evento específico ocorreu. O artigo citado acima do Fábio Souza, pode te ajudar a entender máscaras binárias!

 

Os grupos de eventos são muito importantes em diversos ecossistemas, já que permite a propagação global de eventos (broadcast) por todas tarefas. Muito similar aos semáforos e queues, é de importância para qualquer projetista que pretende seguir com RTOS.

 

Saiba mais

 

Desenvolvendo com o Zephyr RTOS: Controlando o Kernel

Primeiras impressões com o react.o

Fila circular para sistemas embarcados

 

Referências

 

https://www.freertos.org/event-groups-API.html

https://freertos.org/Documentation/RTOS_book.html

http://esp-idf.readthedocs.io/en/latest/api-reference/system/freertos.html

Outros artigos da série

<< RTOS: Uso de Queue para sincronização e comunicação de tarefasRTOS: Software Timer no FreeRTOS >>

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

José Morais
Estudante de Engenharia da Computação pela USC, pretende se aprimorar e fazer a diferença nesta imensa área da tecnologia. Apaixonado por IoT, sistemas embarcados, microcontroladores e integração da computação nos mais diversos fins práticos e didáticos.

2
Deixe um comentário

avatar
 
1 Comment threads
1 Thread replies
2 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
José MoraisYuri Lima Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Yuri Lima
Visitante
Yuri Lima

Show de bola, Jose Morais. Esses conteúdos estão cada vez melhores. Parabéns!!!