【问题标题】:Why don't these goroutines block?为什么这些 goroutines 不阻塞?
【发布时间】:2018-11-05 16:01:58
【问题描述】:

我希望这两个 goroutine 永远阻塞,原因如下,但事实并非如此。为什么?

  1. 通道没有缓冲区,将等待receive() 接收。

  2. send() 持有锁,所以receive() 中的num := <-s.ch 没有机会执行。

  3. 永久阻止

怎么了?

package main

import (
    "sync"
    "fmt"
)

type S struct {
    mu sync.Mutex
    ch chan int
    wg sync.WaitGroup
}

func (s *S) send() {
    s.mu.Lock()
    s.ch <- 5
    s.mu.Unlock()
    s.wg.Done()
}
func (s *S) receive() {
    num := <-s.ch
    fmt.Printf("%d\n", num)
    s.wg.Done()
}

func main() {
    s := new(S)
    s.ch = make(chan int)
    s.wg.Add(2)
    go s.send()
    go s.receive()
    s.wg.Wait()
}

【问题讨论】:

    标签: go mutex channel goroutine


    【解决方案1】:

    你的receive()方法没有使用锁,所以send()持有锁对receive()没有影响。

    而且由于send()receive() 都在它们自己的goroutine 中运行,send() 将使它在通道上发送值5,因此receive() 中的接收可以继续, 它将在下一行打印出来。

    还要注意,要使用来自多个 goroutine 的通道,您不需要“外部”同步。通道对于并发使用是安全的,设计上不会发生数据竞争。详情见If I am using channels properly should I need to use mutexes?

    如果receive() 方法也会像这样使用锁:

    func (s *S) receive() {
        s.mu.Lock()
        num := <-s.ch
        s.mu.Unlock()
        fmt.Printf("%d\n", num)
    }
    

    那么是的,不会打印任何内容,因为在send() 释放锁之前不会发生接收,但是直到有人从通道接收时才会发生。

    在这种情况下,程序将在 1 秒后终止而不打印任何内容,因为当睡眠结束时,主 goroutine 结束,你的整个应用程序也随之结束。它不会等待其他非主 goroutine 完成。详情请见No output from goroutine in Go

    编辑:

    是的,你误解了锁。锁定 sync.Mutex 只会锁定互斥锁值本身,它不会锁定整个结构值(它不能)。 “锁定值本身”意味着如果另一个 goroutine 也调用了它的 Mutex.Lock() 方法,那么该调用将阻塞,直到通过调用它的 Mutex.Unlock() 方法释放锁。解锁后,在 Mutex.Lock() 调用中被阻塞的 goroutine 将继续锁定互斥体并返回。

    【讨论】:

    • 变量ssend()函数锁定。而receive() 尝试从s.ch 读取变量,所以它必须等待锁被解锁。我误解了Mutex吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多