← Voltar ao Encontro 7
Sistemas Operacionais · ADS23
01 / 14
Encontro 7 de 17

Concorrência,
Condição de Corrida
e Exclusão Mútua

O bug mais traiçoeiro que existe: um código que funciona perfeitamente sozinho — e quebra, de forma imprevisível, só quando dois processos rodam ao mesmo tempo.

ADS23IFCE Campus HorizonteProf. José Stelio Sampaio Bastos Neto
↓ role pra avançar · use os pontos à direita pra navegar direto
De onde viemos

Multiplexação explicou o "como". Hoje: o que pode dar errado.

Encontro 6

Vários processos, uma CPU repartida

O escalonador troca de processo tão rápido que parece que tudo roda ao mesmo tempo — concorrência.

Hoje

E se dois processos mexerem no mesmo dado?

Quando dois processos concorrem por um mesmo recurso compartilhado, a ordem exata das trocas de CPU passa a importar — e muito.

Pergunta pra turma

A conta tem R$ 100. Dois caixas depositam R$ 100 nela, ao mesmo tempo.
Por que o saldo final pode virar R$ 200 — em vez de R$ 300?

Cada caixa, sozinho, faz a conta certa. O problema não está na lógica de nenhum dos dois — está na simultaneidade.

Conceito-base

Condição de corrida (race condition)

Acontece sempre que dois ou mais processos acessam um dado compartilhado, e o resultado final depende de quem chega primeiro — uma corrida cujo vencedor muda a cada execução.

Sozinho

Código correto

Um processo lê o saldo, soma R$ 100, grava de volta. Sem concorrência, sempre dá certo.

Concorrente

Mesmo código, resultado errado

Dois processos fazem exatamente essa sequência ao mesmo tempo — e o resultado passa a depender do acaso.

Por dentro do bug

"Somar R$ 100" não é uma operação só — são três

Ler o saldo, somar na memória do processo, e gravar de volta. O escalonador pode trocar de processo entre qualquer uma dessas três etapas — e é exatamente aí que o bug nasce.

Tempo
Caixa A
Caixa B
t0
lê saldo: 100
—
t1
calcula 100+100=200
(escalonador troca)
t2
—
lê saldo: 100 (ainda não gravado!)
t3
grava saldo = 200
calcula 100+100=200
t4
—
grava saldo = 200 (sobrescreve!)

Resultado final: R$ 200, não R$ 300 — o depósito do Caixa A foi perdido, porque o Caixa B leu o saldo antes de A terminar de gravar.

Dando nome ao trecho perigoso

Região crítica: o pedaço de código que mexe no dado compartilhado

É exatamente o trecho "ler → calcular → gravar" do slide anterior. Enquanto um processo está dentro dessa região, nenhum outro processo pode entrar nela ao mesmo tempo — senão a corrida acontece de novo.

Antes da região crítica — código comum, sem risco
REGIÃO CRÍTICA — lê, calcula e grava o saldo compartilhado
Depois da região crítica — código comum, sem risco
A solução, em uma frase

Exclusão mútua: só um processo por vez dentro da região crítica

Se o Caixa B tivesse que esperar o Caixa A terminar de gravar antes de sequer começar a ler o saldo, a corrida nunca aconteceria. Garantir isso é o papel da exclusão mútua.

Sem exclusão mútua

Processos entram livremente

Qualquer um pode entrar na região crítica a qualquer momento — mesmo com outro processo já lá dentro.

Com exclusão mútua

Um de cada vez, na fila

Enquanto um processo está na região crítica, todos os outros que tentarem entrar ficam bloqueados esperando a vez.

O que uma solução precisa garantir

Quatro condições que toda solução de exclusão mútua deve cumprir

Essas quatro regras (Tanenbaum) são o critério pra avaliar qualquer mecanismo de sincronização que vocês encontrarem depois — semáforos, mutexes, locks.

Uma solução ingênua (e seu problema)

Espera ocupada: funciona, mas desperdiça CPU

A forma mais simples de esperar a vez é ficar num laço checando repetidamente "já posso entrar?" — isso é espera ocupada. Resolve a exclusão mútua, mas o processo que espera consome CPU o tempo todo, só checando.

Problema

O processo em espera fica "girando" na CPU sem fazer trabalho útil — o oposto de eficiente.

Caminho melhor (aprofundamento opcional)

Mecanismos como mutexes e semáforos colocam o processo em espera no estado bloqueado, sem gastar CPU — leitura ⚪ de hoje.

Por que isso importa pra quem programa

Concorrência mal tratada é bug intermitente de produção

Esse é o tipo de bug que "funciona na minha máquina", passa nos testes, e falha esporadicamente em produção — porque só aparece sob uma ordem específica de execução, difícil de reproduzir.

Onde aparece

Threads, bancos de dados, arquivos compartilhados

Qualquer recurso acessado por mais de um processo ou thread ao mesmo tempo é candidato a condição de corrida.

Como se proteger

Transações, locks, exclusão mútua

Bancos de dados usam transações; código concorrente usa locks/mutexes — todos aplicando a mesma ideia de hoje.

Eixo do curso

Ensaio de entrega: sua equipe sobe e derruba o container da N2

A N2 (Encontro 8) pede uma defesa com o container do projeto rodando ao vivo. Hoje é o ensaio: cada equipe pratica o ciclo completo — construir, subir, mostrar funcionando, e derrubar — sem surpresas no dia da defesa.

O que ensaiar

docker build → docker run → demonstração → docker stop

O ciclo inteiro, do zero, cronometrado — igual ao que a equipe vai fazer na defesa da N2.

Por que ensaiar agora

Erros de ambiente aparecem antes da nota valer

Container que não sobe, porta ocupada, Dockerfile desatualizado — melhor descobrir hoje do que durante a defesa.

Prévia da prática

Da corrida bancária ao ensaio do container da equipe

Uma sequência real: rodar o script que expõe a condição de corrida, e depois o ciclo completo de ensaio do container.

Cada uma dessas linhas vira um passo do roteiro de laboratório de hoje.

Mão na massa

De ver o bug acontecer a garantir que o container sobe

DIAGNÓSTICO

Condição de corrida na prática

Rodar um script simples que expõe o bug de contagem concorrente, repetidas vezes, e observar resultados diferentes.

ENSAIO N2

Sobe/derruba do container da equipe

Cada equipe cronometra o próprio ciclo de build → run → demonstração → stop.

O roteiro de laboratório detalha os passos, com dicas se algo travar.

Para ler

Leitura da semana

🔵

Tanenbaum — Condições de corrida e Regiões críticas

A base teórica de hoje, direto da fonte — o Laureano não desdobra concorrência, então esta leitura é a referência principal do encontro. p. 82–84

⚪

Tanenbaum — Da espera ocupada aos mutexes + Problemas clássicos de IPC

Pra quem quer entender os mecanismos reais de sincronização além do conceito básico. p. 84–94 e 115–119

O quiz da semana verifica essa leitura e recolhe suas observações da prática — tudo no mesmo instrumento.