Algum tempo atrás, publicamos um post aqui no blog explicando como resolver race condition utilizando mutex e channels.
Embora o conteúdo daquele post continue sendo válido, para alguns casos mais simples de race condition, como por exemplo o do post, podemos utilizar o package sync/atomic
para nos auxiliar.
Para dar o ponta pé inicial, vamos escrever um código que não irá funcionar corretamente por haver race condition.
package main import ( "fmt" "sync" ) func main() { var total int64 var wg sync.WaitGroup for i := 0; i < 50; i++ { wg.Add(1) go func() { for c := 0; c < 1000; c++ { total += int64(c) } wg.Done() }() } wg.Wait() fmt.Println(total) }
Esse simples programa irá iniciar 50 goroutines, onde cada uma delas irá somar o valor de c
(que vai de 0 até 999) à variável total
. Reparem também que é preciso fazer um casting de c
, pois seu tipo será int
e precisamos que eles seja int64
.
Ao executar esse código 3 vezes, obtive os seguintes resultados:

Claramente o programa não está funcionando corretamente. Isso acontece pois não existe nenhum controle de acesso a variável total
, ou seja, não existe uma garantia que a cada iteração do looping dentro das 50 goroutines, o valor da variável é realmente o último atualizado.
Como eu disse no inicio do post, podemos utilizar mutex ou channels para resolver esse problema. No entanto, devido ao tamanho de sua simplicidade, vamos utilizar o package sync/atomic
.
Se você ainda não conhece, esse package fornece algumas funções que nos ajudam a lidar com sincronização e estado de variáveis que são acessadas simultaneamente por múltiplas goroutines. Em outras palavras, ele nos ajuda a resolver o problema que estamos tendo nesse programa.
Resolvendo o race condition
Na linha 19, onde fazemos o total += int64(c)
, vamos mudar para o seguinte código:
atomic.AddInt64(&total, int64(c))
Agora, ao realizar 3 execuções do programa novamente, os resultados que obtive foram:

Problema resolvido de forma simples e elegante.
PONTO DE ATENÇÃO!!!
Como a própria documentação diz, as funções contidas nesse package requerem muito cuidado para serem utilizadas de forma correta. Exceto para alguns casos especiais, a melhor forma de lidar com sincronização é através de channels ou ferramentas fornecidas pelo package sync
.
Deixem suas dúvidas nos comentários.
Até a próxima!
[…] Como acessar uma variável entre goroutines com package sync/atomic […]
[…] Como acessar uma variável entre goroutines com package sync/atomic […]