使用互斥锁 - 仍然是死锁

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
}

https://play.golang.org/p/P5P9Bf5ZSIP

这里的问题与您正在使用的频道有关,因为它是无缓冲的。无缓冲通道将阻塞,直到有接收者接收消息。

这里主要的 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
}

https://play.golang.org/p/QDXuDH0RGPC

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 来自那个通道。