# Condição de corrida

Uma condição de corrida é uma falha num sistema ou processo em que o resultado do processo é inesperadamente dependente da sequência ou sincronia doutros eventos. Apesar de ser conhecido em português por 'condição de corrida' uma tradução melhor seria 'condição de concorrência' pois o problema está relacionado justamente ao gerenciamento da concorrência entre processos teoricamente simultâneos.O fenômeno pode ocorrer em sistemas eletrônicos, especialmente em circuitos lógicos, e em programas de computador, especialmente no uso de multitarefa ou computação distribuída.

## Computação

Condições de corrida acontecem em programas de computador quando diferentes processos ou threads em execução dependem de um estado compartilhado, e o resultado depende do escalonamento dos processos. Por exemplo, assumindo que duas threads T1 e T2 desejam incrementar em um o valor duma variável global inteira. Idealmente, a seguinte sequência de operações ocorre:
| Instrução | Efeito |
| Declara-se a variável local i | Inteiro i = 0 |
| T1 lê o valor de i da memória e armazena no registrador1 | registrador1 ← i :: registrador1 = 0 |
| T1 incrementa o valor de i no registrador1 | registrador1 ← registrador1 + 1 :: registrador1 = 1 |
| T1 armazena o valor do registrador1 na memória | i ← registrador1 :: i = 1 |
| T2 lê o valor de i na memória no registrador2 | registrador2 ← i :: registrador2 = 1 |
| T2 incrementa o valor de i no registrador2 | registrador2 ← registrador2 + 1 :: registrador2 = 2 |
| T2 armazena o valor do registrador2 na memória | i ← registrador2 :: i = 2 |
No caso acima, o valor final é 2, como esperado. Entretanto, se as duas threads são executadas simultaneamente sem um mecanismo de exclusão mútua, o resultado da operação pode ser errado. Uma sequência alternativa de operações é mostrada abaixo:
| Instrução | Efeito |
| Declara-se a variável local i | Inteiro i = 0 |
| T1 lê o valor de i da memória e armazena no registrador1 | registrador1 ← i :: registrador1 = 0 |
| T2 lê o valor de i na memória e armazena no registrador2 | registrador2 ← i :: registrador2 = 0 |
| T1 incrementa o valor de i no registrador1 | registrador1 ← registrador1 + 1 :: registrador1 = 1 |
| T2 incrementa o valor de i no registrador2 | registrador2 ← registrador2 + 1 :: registrador2 = 1 |
| T1 armazena o valor do registrador1 na memória | i ← registrador1 :: i = 1 |
| T2 armazena o valor do registrador2 na memória | i ← registrador2 :: i = 1 |
O valor final de i é 1 ao invés de 2, o esperado. Isso ocorre porque as operações de incremento do segundo caso não são atômicas, isto é, as operações são interrompidas enquanto estão acessando um recurso em comum (a área de memória de i). No primeiro caso, T1 não foi interrompida enquanto estava acessado a variável i, portanto a operação foi atômica e não houve problemas.
Para evitar o problema acima deve-se implementar uma forma de exclusão mútua, definindo regiões críticas do processo.

### Casos práticos
#### Sistemas de arquivos

Em sistemas de arquivos, dois ou mais programas podem tentar acessar ou modificar um mesmo arquivo simultaneamente, o que pode resultar em corrupção de dados. Esse problema é evitável através duma exclusão mútua do arquivo, uma trava de acesso em que o primeiro a requisitar o arquivo tem direito exclusivo ao seu uso. Outra solução é a reorganização do sistema de forma que um único processo é responsável pelo arquivo, e qualquer outro processo que necessite dos dados deve se comunicar com o processo responsável. Isso também requer exclusão mútua, ao nível do processo (o processo responsável pelo arquivo torna-se o "recurso").
Uma forma diferente de condição de corrida existe em sistemas de arquivos em que programas não relacionados afetam uns aos outros pelo uso dos recursos disponíveis do sistema, como espaço de memória (disco rígido, RAM) ou ciclos do processador. Há casos em que o software não é desenvolvido cuidadosamente para antecipar e lidar com as raras situações em que não há memória disponível, e a falta dum tratamento adequado para o caso pode tornar o sistema frágil e imprevisível. Uma solução é o programa de computador alocar e reservar todos os recursos que necessita antes de começar uma tarefa; se a alocação falha, a tarefa é adiada, evitando pontos de falha e de indefinição. Um exemplo prático foi a quase perda da sonda espacial Spirit pouco após sua aterrissagem em Marte: após problemas no sistema e comportamento inadequado, através de depuração chegou-se a conclusão que havia mais arquivos no sistema de arquivos do que ele comportava.

#### Redes de computadores

Em redes de computadores, considere uma rede distribuída de bate-papo como o IRC, em que um utilizador adquire os privilégios de operador do canal em qualquer canal que ele inicie. Se dois utilizadores em diferentes servidores e diferentes nós da mesma rede tentam iniciar o mesmo canal (mesmo nome) ao mesmo tempo, o servidor de cada utilizador definirá o privilégio de operador do canal para cada seu respectivo utilizador. Isso acontece pois nenhum dos servidores recebe o sinal do outro de que o canal já havia sido alocado.
Nesse caso de condição de corrida, o conceito de recurso compartilhado inclui o estado da rede (quais canais existem, assim como quais utilizadores os iniciaram e, portanto, quem tem o privilégio de operador), que cada servidor pode modificar desde que sinalize os outros na rede para que cada um "visualize" o estado global da rede. Entretanto, a latência da rede permite a condição de corrida descrita acima. Uma solução para o caso é eleger somente um servidor para armazenar o estado da rede (canais abertos, informações sobre operadores), ou reconhecer a condição de corrida e corrigir quaisquer erros que ela gere (incluindo uma marca temporal da abertura do canal para julgar quem abriu o canal antes, depois dos dois canais terem sido abertos).