Golang Go语言中下面的代码中,为什么第 17 行的 c.L.Lock() 不会一直等待锁?

发布于 1周前 作者 eggper 来自 Go语言

各位大佬,下面的 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()
}

}


Golang Go语言中下面的代码中,为什么第 17 行的 c.L.Lock() 不会一直等待锁?

更多关于Golang Go语言中下面的代码中,为什么第 17 行的 c.L.Lock() 不会一直等待锁?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

11 回复

我不懂 go ,但是我猜是这行的问题
for len(queue) == 2 {
是 for 还是 if 来的?

更多关于Golang Go语言中下面的代码中,为什么第 17 行的 c.L.Lock() 不会一直等待锁?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


看了下,还真是 for

这个地方是 for

len(queue) >= 2

不好意思发错了

#来自网上的信息# 调用 Wait 会自动释放锁 c.L ,并挂起调用者所在的 goroutine ,因此当前协程会阻塞在 Wait 方法调用的地方。如果其他协程调用了 Signal 或 Broadcast 唤醒了该协程,那么 Wait 方法在结束阻塞时,会重新给 c.L 加锁,并且继续执行 Wait 后面的代码。

对的,因为条件变量就是这么用的,或者说就是这么设计的

这是基础的并发原语之一,各 api 下设计都类似
eg.

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

pthread:

<br>....<br>int<br> pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);<br>....<br>

明白了,非常感谢

文档中的注释
// 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:

在Golang(Go语言)中,c.L.Lock() 不会一直等待锁的原因通常与互斥锁(Mutex)和读写锁(RWMutex)的行为特性有关。这里假设 c.L 是一个 sync.RWMutex 类型的锁。

  1. 读写锁的特性sync.RWMutex 允许多个读操作并发进行,但写操作是互斥的。当有读锁被持有时,其他读锁可以继续获取,但写锁会被阻塞。反过来,当写锁被持有时,任何新的读锁或写锁都会被阻塞。

  2. 锁的状态:如果在第17行调用 c.L.Lock() 时,没有写锁被持有,但有一个或多个读锁被持有,c.L.Lock() 会等待所有读锁被释放。但是,如果已经有写锁被持有,那么 c.L.Lock() 将会一直等待直到写锁被释放。

  3. 不会一直等待的情况:如果第17行 c.L.Lock() 没有一直等待锁,可能是因为:

    • 在调用 c.L.Lock() 之前,所有读锁和写锁都已经被释放。
    • 代码中可能存在其他逻辑(如超时机制、条件变量等)导致 c.L.Lock() 的调用被提前中断或跳过。
    • 并发执行的其他goroutine可能在 c.L.Lock() 调用之前释放了锁。

综上所述,c.L.Lock() 不会一直等待锁的最可能原因是锁在调用前已经是可用的(即没有被其他读锁或写锁持有)。检查锁的使用情况和并发逻辑是理解这一行为的关键。

回到顶部