No exemplo anterior, foi apresentado como gerenciar estados de contadores simples usando atomic operations. Para estados mais complexos é recomendado utilizar mutex para acessar dados entre múltiplas goroutines seguramente. MutEx é abreviação de Mutual Exclusion |
|
package main |
|
import ( "fmt" "sync" ) |
|
A struct container possui um map de contadores;
como a intenção aqui é atualizar concorrentemente
a partir de múltiplas goroutines, é adicionado |
type Container struct { mu sync.Mutex counters map[string]int } |
Trava o mutex antes de acessar |
func (c *Container) inc(name string) { |
c.mu.Lock() defer c.mu.Unlock() c.counters[name]++ } |
|
Note que o valor padrão, ou zero, de um mutex é utilizável, então não é necessária a inicialização aqui. |
func main() { c := Container{ |
counters: map[string]int{"a": 0, "b": 0}, } |
|
var wg sync.WaitGroup |
|
Esta função incrementa, em um loop, um contador de determinado nome. |
doIncrement := func(name string, n int) { for i := 0; i < n; i++ { c.inc(name) } wg.Done() } |
Executando várias goroutines concorrentemente;
Note que todas tem acesso ao mesmo |
wg.Add(3) go doIncrement("a", 10000) go doIncrement("a", 10000) go doIncrement("b", 10000) |
Aguarda todas as goroutines finalizarem. |
wg.Wait() fmt.Println(c.counters) } |
Executando o programa, é exibido que os contadores foram atualizados, conforme esperado. |
$ go run mutexes.go map[a:20000 b:10000] |
Em seguida, será apresentado como implementar este mesmo gerenciamento de estado de tarefas usando apenas goroutines e canais. |
Próximo exemplo: Stateful Goroutines.