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!
Faça parte da comunidade!
Receba os melhores conteúdos sobre Go, Kubernetes, arquitetura de software, Cloud e esteja sempre atualizado com as tendências e práticas do mercado.
Livros Recomendados
Abaixo listei alguns dos melhores livros que já li sobre GO.





[…] Como acessar uma variável entre goroutines com package sync/atomic […]
[…] Como acessar uma variável entre goroutines com package sync/atomic […]