我在Go中使用信号量库作为示例有以下代码:
package main
import (
"fmt"
"context"
"time"
"golang.org/x/sync/semaphore"
)
// This protects the lockedVar variable
var lock *semaphore.Weighted
// Only one go routine should be able to access this at once
var lockedVar string
func acquireLock() {
err := lock.Acquire(context.TODO(), 1)
if err != nil {
panic(err)
}
}
func releaseLock() {
lock.Release(1)
}
func useLockedVar() {
acquireLock()
fmt.Printf("lockedVar used: %sn", lockedVar)
releaseLock()
}
func causeDeadLock() {
acquireLock()
// calling this from a function that's already
// locked the lockedVar should cause a deadlock.
useLockedVar()
releaseLock()
}
func main() {
lock = semaphore.NewWeighted(1)
lockedVar = "this is the locked var"
// this is only on a separate goroutine so that the standard
// go "deadlock" message doesn't print out.
go causeDeadLock()
// Keep the primary goroutine active.
for true {
time.Sleep(time.Second)
}
}
有没有一种方法可以让acquireLock()
函数调用在超时后打印一条消息,指示存在潜在的死锁,但不取消阻止调用?我希望死锁持续存在,但在达到超时时会写入日志消息。所以TryAcquire并不是我想要的。
我想要的psuedo代码示例:
afterFiveSeconds := func() {
fmt.Printf("there is a potential deadlockn")
}
lock.Acquire(context.TODO(), 1, afterFiveSeconds)
如果Acquire
调用被阻止超过5秒,则本例中的lock.Acquire
调用将调用afterFiveSeconds
回调,但不会解除对调用方的阻止。它将继续阻塞。
我想我已经找到了解决问题的方法。
func acquireLock() {
timeoutChan := make(chan bool)
go func() {
select {
case <-time.After(time.Second * time.Duration(5)):
fmt.Printf("potential deadlock while acquiring semaphoren")
case <-timeoutChan:
break
}
}()
err := lock.Acquire(context.TODO(), 1)
close(timeoutChan)
if err != nil {
panic(err)
}
}