#go
#Вперед
Вопрос:
Я изучаю Go. Я пытаюсь решить проблему взаимоблокировки в подпрограммах, используя семафоры. Я создал две функции, которые записывают данные в небуферизованный канал. чтение происходит по основному каналу. предполагается, что третья функция закрывает канал. когда я запускаю программу, она выдает эту ошибку неустранимая ошибка: все программы находятся в спящем режиме — взаимоблокировка! может кто-нибудь объяснить мне, почему это не работает.
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var s = []string{"a", "b", "c", "d"}
var w = []string{"w", "x", "t", "z", "p"}
func f(c chan string, ch chan bool) {
for _, word := range s {
c <- word
}
fmt.Println("f about to exit")
ch <- true
wg.Done()
}
func g(c chan string, ch chan bool) {
for _, word := range w {
c <- word
}
fmt.Println("g about to exit")
ch <- true
wg.Done()
}
func f1(ch chan string, c chan bool) {
<-c
<-c
fmt.Println("about to close channel")
close(ch)
}
func main() {
ch := make(chan string)
c := make(chan bool)
wg.Add(3)
go f(ch, c)
go g(ch, c)
go f1(ch, c)
for word := range ch {
fmt.Println(word)
}
wg.Wait()
}
Ответ №1:
Вы должны быть последовательны в именовании канала данных и канала сигнализации.
Вот и все.
Здесь у вас есть две процедуры перехода производителя и одна процедура перехода потребителя,
поэтому позвольте мне сначала упростить ваш код, попробуйте это онлайн:
func main() {
ch := make(chan string)
done := make(chan struct{})
go func() {
for _, word := range []string{"1", "2", "3"} {
ch <- word
}
done <- struct{}{}
}()
go func() {
for _, word := range []string{"10", "20", "30", "40"} {
ch <- word
}
done <- struct{}{}
}()
go func() {
<-done
<-done
close(ch)
}()
for word := range ch {
fmt.Print(word, " ")
}
fmt.Println()
}
Вывод:
1 2 10 3 20 30 40
Примечания:
- Вам не нужно
sync.WaitGroup
, поскольку для передачи сигналов достаточно готового канала. - Пустая структура достаточно хороша для сигнализации.
- После получения двух сигналов done вы можете закрыть канал передачи данных, чтобы основной выходил из цикла.
Ответ №2:
После запуска трех подпрограмм вы читаете из канала, ch
пока ch
он не будет закрыт. Все функции получают ch
в качестве первого аргумента, в который они записывают, но f1
записывают в свой второй аргумент, а не в первый. То есть f1
выполняется запись в канал c
в main, поэтому f1
блокируется при первой записи, потому что никто не читает из c
. Основная подпрограмма заблокирована для чтения из, ch
потому что после того, как f
и g
выполнены, в нее никто не записывает.
Это похоже на путаницу в именовании канала: две функции получают (c, ch)
, одна получает (ch, c)
, но все вызываются с помощью (ch, c)
.