使用互斥锁 - 仍然是死锁
Using Mutex lock - still deadlock
我正在玩 Goroutines 和通道,想知道为什么我在标题中出现错误。
这个想法是我有一个全局 int 通道,每个通道都会递增。
通过使用互斥锁,我希望每个例程都能锁定通道,但失败了。
代码在这里:
package main
import (
"fmt"
"sync"
)
var number = make(chan int)
var mutex = &sync.Mutex{}
func worker(wg *sync.WaitGroup, id int) {
defer wg.Done()
mutex.Lock()
number <- id + <-number
mutex.Unlock()
}
func main() {
var wg sync.WaitGroup
number <- 0
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(&wg, i)
}
wg.Wait()
fmt.Println(<-number) // expected output: 0+1+2+3+4 = 10
}
这里的问题与您正在使用的频道有关,因为它是无缓冲的。无缓冲通道将阻塞,直到有接收者接收消息。
这里主要的 go 例程将一个数字添加到通道,然后创建 5 个 go 例程来关闭通道和添加到通道,然后等待它们完成,然后再从通道中取出一个项目。除非有东西从它那里接收数字,否则它不会在通道中添加 0,因此它甚至在到达互斥锁之前就阻塞了。
5 个 go 例程只有在有东西从通道上掉下来时才能完成。
如果您通过向 make 调用提供大小来更改为缓冲通道,那么这将开始 运行 完成:
package main
import (
"fmt"
"sync"
)
var number = make(chan int, 5)
var mutex = &sync.Mutex{}
func worker(wg *sync.WaitGroup, id int) {
defer wg.Done()
mutex.Lock()
number <- id + <-number
mutex.Unlock()
}
func main() {
var wg sync.WaitGroup
number <- 0
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(&wg, i)
}
wg.Wait()
fmt.Println(<-number) // expected output: 0+1+2+3+4 = 10
}
Go 中的 Channel 用于在两个不同的 goroutine 之间进行同步。
一个 goroutine 会等待 read/write 除非它找到另一个 goroutine write/read 到同一个通道(假设通道是无缓冲的)
这意味着该程序将始终存在死锁:
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
done := make(chan bool)
done <- true
<- done
}
因为第 10 行会被阻止寻找另一个从 chan done 读取的 goroutine,但是没有这样的 goroutine。
因此,来自同一个 goroutines 的 writing/reading 会阻塞,除非有其他 goroutines reads/write 来自那个通道。
我正在玩 Goroutines 和通道,想知道为什么我在标题中出现错误。
这个想法是我有一个全局 int 通道,每个通道都会递增。
通过使用互斥锁,我希望每个例程都能锁定通道,但失败了。
代码在这里:
package main
import (
"fmt"
"sync"
)
var number = make(chan int)
var mutex = &sync.Mutex{}
func worker(wg *sync.WaitGroup, id int) {
defer wg.Done()
mutex.Lock()
number <- id + <-number
mutex.Unlock()
}
func main() {
var wg sync.WaitGroup
number <- 0
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(&wg, i)
}
wg.Wait()
fmt.Println(<-number) // expected output: 0+1+2+3+4 = 10
}
这里的问题与您正在使用的频道有关,因为它是无缓冲的。无缓冲通道将阻塞,直到有接收者接收消息。
这里主要的 go 例程将一个数字添加到通道,然后创建 5 个 go 例程来关闭通道和添加到通道,然后等待它们完成,然后再从通道中取出一个项目。除非有东西从它那里接收数字,否则它不会在通道中添加 0,因此它甚至在到达互斥锁之前就阻塞了。
5 个 go 例程只有在有东西从通道上掉下来时才能完成。
如果您通过向 make 调用提供大小来更改为缓冲通道,那么这将开始 运行 完成:
package main
import (
"fmt"
"sync"
)
var number = make(chan int, 5)
var mutex = &sync.Mutex{}
func worker(wg *sync.WaitGroup, id int) {
defer wg.Done()
mutex.Lock()
number <- id + <-number
mutex.Unlock()
}
func main() {
var wg sync.WaitGroup
number <- 0
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(&wg, i)
}
wg.Wait()
fmt.Println(<-number) // expected output: 0+1+2+3+4 = 10
}
Go 中的 Channel 用于在两个不同的 goroutine 之间进行同步。 一个 goroutine 会等待 read/write 除非它找到另一个 goroutine write/read 到同一个通道(假设通道是无缓冲的)
这意味着该程序将始终存在死锁:
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
done := make(chan bool)
done <- true
<- done
}
因为第 10 行会被阻止寻找另一个从 chan done 读取的 goroutine,但是没有这样的 goroutine。
因此,来自同一个 goroutines 的 writing/reading 会阻塞,除非有其他 goroutines reads/write 来自那个通道。