Flags, Semáforos e Eventos no Zephyr: Sinalização e Coordenação de Threads
2.1 O que são “Flags” no contexto do Zephyr?
No Zephyr, o termo flag não aparece como um objeto único e explícito como em alguns RTOS clássicos. Em vez disso, a ideia de sinalização é implementada por meio de semáforos (k_sem), eventos (k_event) e do mecanismo mais avançado de polling (k_poll).
O ponto central é o seguinte:
flags não transportam dados, apenas significado. Elas indicam que algo aconteceu ou que uma condição foi satisfeita. Isso as torna extremamente eficientes para sincronização entre threads, interrupções (ISRs) e até drivers.
2.2 Semáforos (k_sem): a forma mais simples de flag
O semáforo do Zephyr (k_sem) é o mecanismo mais direto para sinalização. Ele pode ser entendido como um contador protegido pelo kernel.
Um semáforo é ideal quando:
- Uma thread precisa esperar outra concluir algo
- Um recurso está disponível ou indisponível
- Um evento ocorre repetidamente
Declaração de um semáforo
#include <zephyr/kernel.h>
K_SEM_DEFINE(meu_sem, 0, 1);
Parâmetros:
- Valor inicial:
0→ começa bloqueado - Valor máximo:
1→ comportamento de flag binária
Esse padrão é extremamente comum.
2.3 Thread aguardando um semáforo (consumidor do evento)
void thread_espera(void)
{
while (1) {
k_sem_take(&meu_sem, K_FOREVER);
printk("Evento recebido!\n");
}
}
Aqui:
- A thread entra em estado bloqueado
- Não consome CPU
- Só é acordada quando o semáforo for liberado
Esse comportamento é determinístico e eficiente energeticamente, essencial para sistemas embarcados.
2.4 Thread ou ISR liberando o semáforo (produtor do evento)
void thread_sinaliza(void)
{
while (1) {
k_sleep(K_SECONDS(2));
k_sem_give(&meu_sem);
}
}
O mesmo código pode ser usado em uma interrupção:
void minha_isr(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
k_sem_give(&meu_sem);
}
O Zephyr garante que k_sem_give() é ISR-safe, algo crítico para aplicações reais.
2.5 Semáforo binário vs semáforo contador
Embora seja comum usar semáforos como flags binárias, o Zephyr permite semáforos contadores.
Exemplo:
K_SEM_DEFINE(buffer_sem, 0, 10);
Isso permite:
- Contabilizar múltiplos eventos
- Modelar filas lógicas
- Controlar acesso a buffers circulares
Porém, quanto maior o contador, maior o risco de esconder problemas de sincronização. Em sistemas críticos, prefira valores pequenos e bem controlados.
2.6 Limitações dos semáforos como flags
Semáforos resolvem muitos problemas, mas têm limitações claras:
- Não permitem múltiplas condições simultâneas
- Não carregam contexto semântico (qual evento ocorreu?)
- Não são ideais para state machines complexas
Quando você precisa esperar mais de uma condição, ou combinar eventos, entra em cena o k_event.
2.7 Eventos (k_event): flags múltiplas em um único objeto
O k_event é um mecanismo poderoso que permite trabalhar com múltiplos bits de evento, de forma semelhante a event flags clássicos.
Declaração:
K_EVENT_DEFINE(meu_evento);
Cada bit do evento representa uma condição distinta.
2.8 Definindo flags de evento
#define EVT_SENSOR_OK BIT(0)
#define EVT_TIMEOUT BIT(1)
#define EVT_ERRO BIT(2)
Essas flags podem ser combinadas livremente.
2.9 Sinalizando eventos
k_event_post(&meu_evento, EVT_SENSOR_OK);
Ou múltiplos eventos de uma vez:
k_event_post(&meu_evento, EVT_SENSOR_OK | EVT_TIMEOUT);
Isso torna o código muito mais expressivo do que múltiplos semáforos espalhados.
2.10 Aguardando eventos
uint32_t eventos;
eventos = k_event_wait(&meu_evento,
EVT_SENSOR_OK | EVT_ERRO,
false,
K_FOREVER);
if (eventos & EVT_SENSOR_OK) {
printk("Sensor OK\n");
}
if (eventos & EVT_ERRO) {
printk("Erro detectado\n");
}
Parâmetros importantes:
- Máscara de eventos esperados
reset = false→ evento permanece ativo- Timeout configurável
Esse modelo é ideal para máquinas de estado, drivers e sistemas reativos.
2.11 Quando usar k_sem vs k_event
Use k_sem quando:
- Um único evento importa
- Simplicidade é prioridade
- Código precisa ser extremamente leve
Use k_event quando:
- Vários eventos precisam ser monitorados
- Há múltiplas fontes de sinalização
- A lógica depende da combinação de estados
2.12 Erros comuns com Flags e Eventos
Alguns problemas recorrentes em projetos reais:
- Usar múltiplos semáforos onde um evento resolveria
- Não limpar eventos corretamente
- Criar dependência circular de eventos
- Tratar eventos como filas de dados (erro conceitual)
Esses erros geralmente aparecem como travamentos intermitentes, difíceis de depurar.