为什么这些 goroutines 不阻塞?

Why don't these goroutines block?

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

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

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

  3. 永远阻止[=​​15=]

怎么了?

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()
}

您的 receive() 方法不使用锁,因此 send() 持有锁对 receive() 没有影响。

并且由于 send()receive() 运行 在他们自己的 goroutine 中,send() 将到达发送值 5 的位置在通道上,因此 receive() 中的接收可以继续,并且会在下一行打印出来。

另请注意,要使用来自多个 goroutine 的通道,您不需要 "external" 同步。通道对于并发使用是安全的,数据竞争不会因设计而发生。有关详细信息,请参阅

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

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

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

在这种情况下,程序将在 1 秒后终止而不打印任何内容,因为当睡眠结束时,主 goroutine 结束,整个应用程序也会随之结束。它不会等待其他非主 goroutines 完成。有关详细信息,请参阅

编辑:

是的,你对锁的理解有误。锁定 sync.Mutex 只会锁定互斥锁值本身,它不会锁定整个结构值(它不能)。 "locks the value itself" 意味着如果另一个 goroutine 也调用它的 Mutex.Lock() 方法,该调用将阻塞,直到通过调用它的 Mutex.Unlock() 方法释放锁。解锁后,在 Mutex.Lock() 调用时阻塞的 goroutine 将继续锁定互斥锁和 return.