O que você vai aprender
Explicar a condição de corrida e a necessidade de exclusão mútua.
Usar semáforos e monitores para sincronizar.
Reconhecer e resolver a inversão de prioridade.
Relacionar instruções atômicas de hardware às travas.
Quando 1 + 1 não dá 2
Duas threads incrementam o mesmo contador, cada uma 1000 vezes. O resultado esperado é 2000 — mas, sem cuidado, pode dar 1500, 1800, qualquer coisa. Por quê? Porque "incrementar" não é uma operação atômica.
Esta aula trata de como threads e processos coordenam o acesso a recursos compartilhados sem corromper dados — e do perigo sutil que isso traz para o tempo real: a inversão de prioridade.
Roteiro da aula
de corrida→Semáforos e
monitores→Inversão de
prioridade→Herança de
prioridade
Do problema (races) às ferramentas (semáforos, monitores, instruções atômicas) e ao caso especial do tempo real.
Condição de corrida e seção crítica
Seção crítica. Trecho de código que acessa o recurso compartilhado e deve ser executado por uma thread de cada vez.
Por que o incremento não é atômico
A instrução contador++ em alto nível esconde três passos em hardware: ler o valor da memória para um registrador, somar 1, escrever de volta. Se duas threads intercalam esses passos, ambas leem o mesmo valor antigo e uma sobrescreve a outra — um incremento se perde.
A solução é garantir exclusão mútua: cercar a seção crítica de modo que apenas uma thread por vez execute aquele trecho. As propriedades desejadas são: exclusão mútua, progresso (não bloquear sem necessidade) e espera limitada (sem inanição).
A intercalação fatal
A ordem de execução, fora do controle do programador, mudou o resultado. Eis a condição de corrida em ação.
Passo a passo: produtor-consumidor
Semáforos e monitores
wait/P (decrementa, bloqueia se ficaria negativo) e signal/V (incrementa, libera quem espera).Monitor. Construção de alto nível que encapsula dados + operações com exclusão mútua automática e variáveis de condição.
Semáforo binário, contador e monitor
Um semáforo binário (valores 0/1) funciona como um mutex: protege uma seção crítica. Um semáforo contador conta recursos disponíveis (ex.: vagas num buffer). A operação wait/signal deve ser atômica — implementada com apoio do hardware.
O monitor eleva o nível de abstração: a exclusão mútua é embutida e variáveis de condição (wait/signal sobre condições) coordenam a espera por eventos.
A tranca do banheiro
Semáforo vs. monitor
| Aspecto | Semáforo | Monitor |
|---|---|---|
| Nível | Baixo nível | Alto nível |
| Exclusão mútua | Manual (o programador chama wait/signal) | Automática (embutida) |
| Risco de erro | Alto (esquecer um signal trava tudo) | Menor (a estrutura cuida) |
| Espera por condição | Com semáforos auxiliares | Variáveis de condição nativas |
Da instrução atômica à trava
(TAS / CAS)→Lock /
mutex→Semáforo /
monitor→Programa
correto
test-and-set (TAS) e compare-and-swap (CAS) leem e escrevem em um único passo indivisível — a base para construir travas sem condição de corrida na própria trava.A inversão de prioridade
É um problema clássico e perigoso em tempo real: a tarefa de alta prioridade "espera" não pela baixa diretamente, mas pelas médias que monopolizam a CPU enquanto a baixa segura o recurso. O prazo da tarefa alta pode estourar.
Verifique seu entendimento
Na inversão de prioridade, o que de fato atrasa a tarefa de ALTA prioridade?
Mars Pathfinder (1997)
A sonda Mars Pathfinder começou a reiniciar repetidamente em Marte. A causa: inversão de prioridade. Uma tarefa de alta prioridade (gestão do barramento) esperava um mutex segurado por uma tarefa de baixa prioridade (meteorologia), que era constantemente preemptada por tarefas de prioridade média. Um watchdog detectava o atraso e reiniciava o sistema.
A correção foi enviada remotamente: ativar a herança de prioridade no semáforo. É o exemplo canônico de por que sincronização em tempo real é assunto sério — aqui, a milhões de quilômetros de distância.
Armadilhas de sincronização
• Esquecer um
signal → o recurso fica travado para sempre (deadlock).• Adquirir locks em ordens diferentes em threads distintas → deadlock (Aula 7).
• Seções críticas grandes demais → serializam o programa e matam o paralelismo.
• Ignorar a inversão de prioridade em sistemas de tempo real.
Boas práticas de exclusão mútua
Revele a solução
Como a herança de prioridade resolve a inversão?
Revisão relâmpago
Como isto se liga ao curso
A sincronização conecta:
- As threads e a memória compartilhada (Aula 4), que tornam as races possíveis.
- As instruções atômicas de hardware (Aula 1), que sustentam as travas.
- Os deadlocks (Aula 7), que surgem de locks mal coordenados — wait/signal e ordem de aquisição importam.
Resumo da aula
Atividade em grupo · Resolvendo a inversão
Em trios, encenem e resolvam um caso de inversão de prioridade.
Roteiro
- Definam 3 tarefas: H (alta), M (média) e L (baixa); L segura um mutex que H precisa.
- Tracem a linha do tempo mostrando H bloqueada por L enquanto M roda.
- Apliquem herança de prioridade e refaçam a linha do tempo.
- Comparem a latência de H nos dois casos.
Mini-quiz · Aula 6
20 questões sobre esta aula. Escolha e veja a explicação na hora.
📌 Resumo — leve isto para a prova
- Condições de corrida exigem exclusão mútua na seção crítica.
- Semáforos (wait/signal) e monitores coordenam o acesso compartilhado.
- Instruções atômicas de hardware (TAS, CAS) são a base das travas.
- A inversão de prioridade ameaça o tempo real; a herança de prioridade a resolve.
- Locks mal coordenados levam a deadlocks; seções críticas curtas reduzem riscos.