下面的 Go 代码中,为什么第 17 行的 c.L.Lock() 不会一直等待锁? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
CarrieBauch
V2EX    Go 编程语言
下面的 Go 代码中,为什么第 17 行的 c.L.Lock() 不会一直等待锁?
  •  
  •   CarrieBauch 2023-07-16 18:28:01 +08:00 2034 次点击
    这是一个创建于 825 天前的主题,其中的信息可能已经有所发展或是发生改变。

    各位大佬,下面的 Go 代码中,当主 Goroutine 执行到 c.Wait() 的时候,第 28 行的 c.L.Lock() 肯定执行了,那么当执行到第 17 行的 c.L.Lock(),为什么程序不会一直阻塞呢?

    package main import ( "fmt" "sync" "time" ) // a goroutine that is waiting for a signal, and a goroutine that is sending signals. // Say we have a queue of fixed length 2, and 10 items we want to push onto the queue func main() { c := sync.NewCond(&sync.Mutex{}) queue := make([]interface{}, 0, 10) removeFromQueue := func(delay time.Duration) { time.Sleep(delay) c.L.Lock() // 这是第 17 行,执行到这里为什么不是一直阻塞等待锁? queue = queue[1:] fmt.Println("Removed from queue") c.L.Unlock() c.Signal() // let a goroutine waiting on the condition know that something has ocurred } for i := 0; i < 10; i++ { c.L.Lock() // 这是 28 行,critical section // When the queue is equal to two the main goroutine is suspend // until a signal on the condition has been sent length := len(queue) fmt.Println(length) for len(queue) == 2 { fmt.Println("wait signal") c.Wait() // 这是 36 行,等待 signal ,但是 removeFromQueue 为什么不会一直等待锁呢? } fmt.Println("Adding to queue") queue = append(queue, struct{}{}) go removeFromQueue(10 * time.Second) c.L.Unlock() } } 
    10 条回复    2023-07-17 21:50:29 +08:00
    yankebupt
        1
    yankebupt  
       2023-07-16 18:47:12 +08:00   1
    我不懂 go ,但是我猜是这行的问题
    for len(queue) == 2 {
    是 for 还是 if 来的?
    yankebupt
        2
    yankebupt  
       2023-07-16 18:49:57 +08:00
    看了下,还真是 for
    CarrieBauch
        3
    CarrieBauch  
    OP
       2023-07-16 18:50:31 +08:00
    @yankebupt 这个地方是 for
    trzzzz
        4
    trzzzz  
       2023-07-16 18:51:30 +08:00
    len(queue) >= 2
    trzzzz
        5
    trzzzz  
       2023-07-16 18:53:33 +08:00
    @trzzzz 不好意思发错了
    AnroZ
        6
    AnroZ  
       2023-07-16 19:04:53 +08:00
    #来自网上的信息# 调用 Wait 会自动释放锁 c.L ,并挂起调用者所在的 goroutine ,因此当前协程会阻塞在 Wait 方法调用的地方。如果其他协程调用了 Signal 或 Broadcast 唤醒了该协程,那么 Wait 方法在结束阻塞时,会重新给 c.L 加锁,并且继续执行 Wait 后面的代码。
    thevita
        7
    thevita  
       2023-07-16 19:11:57 +08:00
    @AnroZ 对的,因为条件变量就是这么用的,或者说就是这么设计的
    thevita
        8
    thevita  
       2023-07-16 19:15:53 +08:00   1
    这是基础的并发原语之一,各 api 下设计都类似
    eg.

    cpp: https://en.cppreference.com/w/cpp/thread/condition_variable

    pthread:

    ```
    ....
    int
    pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
    ....
    ```
    CarrieBauch
        9
    CarrieBauch  
    OP
       2023-07-16 19:20:21 +08:00
    @AnroZ 明白了,非常感谢
    Jooeeee
        10
    Jooeeee  
       2023-07-17 21:50:29 +08:00
    文档中的注释
    // Wait atomically unlocks c.L and suspends execution
    // of the calling goroutine. After later resuming execution,
    // Wait locks c.L before returning. Unlike in other systems,
    // Wait cannot return unless awoken by Broadcast or Signal.
    //
    // Because c.L is not locked while Wait is waiting, the caller
    // typically cannot assume that the condition is true when
    // Wait returns. Instead, the caller should Wait in a loop:
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2664 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 43ms UTC 09:18 PVG 17:18 LAX 02:18 JFK 05:18
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86