Eu tenho o seguinte código. É um exercício de aprendizado, então ele não faz nada obviamente útil. Se o valor wg.Add for 1, ele funciona. Se o valor wg.Add for 2, ele falha. Se eu remover a lógica do canal, ele funciona com um valor wg.Add de 2.
Alguma ideia do que estou fazendo errado?
package main
import (
"fmt"
"sync"
)
func popMessage(wg *sync.WaitGroup, m *sync.Mutex, i *int, c chan<- int) {
m.Lock()
*i++
c <- *i
m.Unlock()
fmt.Printf("pop %d\n", *i)
wg.Done()
}
func main() {
var wg sync.WaitGroup
var m sync.Mutex
var intPtr *int
c := make(chan int, 1)
wg.Add(2)
intPtr = new(int)
*intPtr = 1
go popMessage(&wg, &m, intPtr, c)
go popMessage(&wg, &m, intPtr, c)
go popMessage(&wg, &m, intPtr, c)
wg.Wait()
fmt.Printf("final %d\n", *intPtr)
for x := range c {
fmt.Printf("channel %d\n", x)
}
}
A
wg.Wait()
função bloqueará até que oWaitGroup
contador chegue a zero. No seu caso, você inicializou o contador comwg.Add(2)
, o que significa quewg.Wait()
esperará quewg.Done()
seja chamado duas vezes antes de prosseguir.Você também criou um canal com buffer com capacidade de 1 (
c := make(chan int, 1)
). Isso significa que o canal pode conter apenas um valor em seu buffer. Quando o buffer estiver cheio, qualquer operação de envio adicional (c <- value
) será bloqueada até que uma goroutine receba um valor do canal (<-c
), liberando espaço no buffer.No seu código, depois que um valor é enviado ao canal, o buffer fica cheio. Quaisquer operações de envio subsequentes (
c <- *i
) serão bloqueadas porque o canal não tem espaço disponível. Como resultado, apenas uma goroutine chama com sucessowg.Done()
, enquanto as outras goroutines permanecem bloqueadas, esperando para enviar seus dados.Isso leva a um deadlock:
wg.Wait()
está esperando pela segundawg.Done()
chamada, mas a segunda goroutine está travada tentando enviar dados para o canal. Consequentemente, seu programa trava indefinidamente.CONSERTAR:
E escreva este código acima do for-loop e abaixo
wg.Wait()
: