我是GoLang的学习者,正在尝试进行实验并了解Sync软件包和chan概念。
我正在运行并希望在控制台上打印接收通道值的代码,但是该值未得到打印,它有时但并非总是打印该值。
如果我在不使用chan的情况下进行调整,那么它将打印所有通道值,但会失败,并显示错误“ 致命错误:所有goroutine都在睡眠中-死锁!”
我尝试使用通道“完成”来同步通道读取,但是在这种情况下,它再次因相同的错误而开始失败。我还尝试了waitGroup API,您可以在我的代码中看到它(有注释),但这对我没有用。
感谢您的帮助
源代码:
package main
import (
"fmt"
"sync"
)
type safeOperation struct {
i int
sync.Mutex
}
var wg sync.WaitGroup
func main() {
so := new(safeOperation)
ch := make(chan int)
//done := make(chan bool)
for i := 0; i < 5; i++ {
go so.Increment(ch)
go so.Decrement(ch)
}
go func() {
//wg.Add(1)
for c := range ch {
fmt.Println("Receiving Channel Value: ", c)
}
//wg.Done()
//done <- true
}()
//wg.Wait()
//<-done
fmt.Println("Value: ", so.GetValue())
fmt.Println("Main method finished")
}
func (so *safeOperation) Increment(ch chan int) {
//so.Lock()
//defer wg.Done()
so.i++
ch <- so.i
//so.Unlock()
}
func (so *safeOperation) Decrement(ch chan int) {
//so.Lock()
//defer wg.Done()
so.i--
ch <- so.i
//so.Unlock()
}
func (so *safeOperation) GetValue() int {
so.Lock()
v := so.i
so.Unlock()
return v
}
输出: 价值:1 主要方法完成
答案 0 :(得分:2)
使用WaitGroup
的一个好方法是在发送到频道之前调用Add()
或使用go
关键字,并在从频道接收后调用Done()
。
这样,您可以确定Add()
总是按时调用,而不管是否在通道块上发送。
我已更改您的示例代码来做到这一点:
package main
import (
"fmt"
"sync"
)
type safeOperation struct {
i int
sync.Mutex
}
var wg sync.WaitGroup
func main() {
so := new(safeOperation)
ch := make(chan int)
for i := 0; i < 5; i++ {
wg.Add(1)
go so.Increment(ch)
wg.Add(1)
go so.Decrement(ch)
}
go func() {
for c := range ch {
fmt.Println("Receiving Channel Value: ", c)
wg.Done()
}
}()
wg.Wait()
//<-done
fmt.Println("Value: ", so.GetValue())
fmt.Println("Main method finished")
}
func (so *safeOperation) Increment(ch chan int) {
so.i++
ch <- so.i
}
func (so *safeOperation) Decrement(ch chan int) {
so.i--
ch <- so.i
}
func (so *safeOperation) GetValue() int {
so.Lock()
v := so.i
so.Unlock()
return v
}
当然,您还希望使用互斥量保护safeOperation.i
(否则其值将不可预测),但这是获得所需输出所必需的。