使用互斥锁-仍然死锁

时间:2019-05-09 03:51:43

标签: go channel goroutine

我正在玩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

2 个答案:

答案 0 :(得分:3)

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

在这里,主执行例程向通道添加了一个数字,然后创建了5个执行例程以既退出通道又添加到通道,然后等待它们完成,然后从通道中取出项目。直到有东西可以接收到该数字后,才能在该通道上添加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

答案 1 :(得分:0)

Go中的通道用于在两个不同的goroutine之间进行同步。 goroutine将等待 read / write ,除非它找到另一个对同一通道进行 write / read 的goroutine(假定通道没有缓冲)

这意味着该程序将始终具有死锁:

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, playground")
    done := make(chan bool)
    done <- true
    <- done
}

因为第10行将被阻塞,以寻找从chan中读取的另一个goroutine,但是没有这样的goroutine。

因此,除非有其他goroutine从该通道读取/写入,否则从同一goroutine写入/读取将被阻止。