为什么这些goroutines不会阻止?

时间:2018-05-26 12:54:05

标签: go mutex channel goroutine

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

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

  2. send()按住该锁定,num := <-s.ch中的receive()无法执行。

  3. 永远阻止

  4. 怎么了?

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

1 个答案:

答案 0 :(得分:2)

您的receive()方法未使用锁定,因此持有锁定的send()receive()无效。

由于send()receive()都在他们自己的goroutine中运行,send()会使其达到在频道上发送值5的程度,因此receive()中的接收可以继续进行,并且会在下一行打印出来。

另请注意,要使用来自多个goroutine的频道,您不需要&#34;外部&#34;同步。通道对于并发使用是安全的,数据竞争不能通过设计发生。有关详细信息,请参阅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仅锁定互斥锁值本身,它不会锁定整个结构值(它不能锁定)。并且&#34;锁定价值本身&#34;表示如果另一个goroutine也调用其Mutex.Lock()方法,该调用将阻塞,直到通过调用其Mutex.Unlock()方法释放锁。解锁后,Mutex.Lock()呼叫阻止的goroutine将继续锁定互斥锁并返回。