首页 > 解决方案 > 使用互斥锁 - 仍然是死锁

问题描述

我正在玩 Goroutine 和通道,想知道为什么我在标题中出现错误。
这个想法是我有一个全局 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

标签: gochannelgoroutine

解决方案


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

在这里,主 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


推荐阅读