如何取消延期声明
How to cancel a deferred statement
我有以下代码结构,其中我在 A 点 Lock() 并且需要在同一函数的 B 点明确 Unlock() 。在 A 点和 B 点之间,我有多个 returns 基于需要 Unlock() 的错误。在A点使用defer lock.Unlock()
解决了万一出现错误锁会被释放的问题。但是,如果执行成功到达 B 点 - 我怎样才能取消延迟和 Unlock() 呢?
func foo() {
...
// point A
lock.Lock()
defer lock.Unlock()
...
err := bar()
if err != nil {
return
}
...
//point B - need to definetely unlock here
//lock.Unlock() ?
}
无法取消延迟函数。
使用局部变量记录函数相对于锁的状态,并在延迟函数中检查该变量。
lock.Lock()
locked := true
defer func() {
if locked {
lock.Unlock()
}
}()
...
err := bar()
if err != nil {
return
}
...
lock.Unlock()
locked = false
...
因为锁一般用在多线程环境下,需要注意的是函数局部变量locked
只能被单个goroutine访问(感谢Rick-777在评论中指出) .
您不能取消延迟函数。
您可以使用 sync.Once
来确保互斥锁被恰好解锁一次:
func foo() {
var unlockOnce sync.Once
// point A
lock.Lock()
defer unlockOnce.Do(lock.Unlock)
...
err := bar()
if err != nil {
return
}
...
// point B - need to unlock here
unlockOnce.Do(lock.Unlock)
}
如果可能,最好重构您的代码,以便锁定的部分保留在单个函数中:
func fooLock() error {
lock.Lock()
defer lock.Unlock()
if err := bar(); err != nil { return err }
...
return nil
}
func foo() {
if err := fooLock(); err != nil { return }
... do the bit that doesn't need a lock
}
显然这里的命名和错误处理是松散的,因为代码是通用的而不是特定的。如果您需要点 B 之前的代码块中的信息(现在位于 fooLock
中的代码中),它可以与错误一起返回。
我有以下代码结构,其中我在 A 点 Lock() 并且需要在同一函数的 B 点明确 Unlock() 。在 A 点和 B 点之间,我有多个 returns 基于需要 Unlock() 的错误。在A点使用defer lock.Unlock()
解决了万一出现错误锁会被释放的问题。但是,如果执行成功到达 B 点 - 我怎样才能取消延迟和 Unlock() 呢?
func foo() {
...
// point A
lock.Lock()
defer lock.Unlock()
...
err := bar()
if err != nil {
return
}
...
//point B - need to definetely unlock here
//lock.Unlock() ?
}
无法取消延迟函数。
使用局部变量记录函数相对于锁的状态,并在延迟函数中检查该变量。
lock.Lock()
locked := true
defer func() {
if locked {
lock.Unlock()
}
}()
...
err := bar()
if err != nil {
return
}
...
lock.Unlock()
locked = false
...
因为锁一般用在多线程环境下,需要注意的是函数局部变量locked
只能被单个goroutine访问(感谢Rick-777在评论中指出) .
您不能取消延迟函数。
您可以使用 sync.Once
来确保互斥锁被恰好解锁一次:
func foo() {
var unlockOnce sync.Once
// point A
lock.Lock()
defer unlockOnce.Do(lock.Unlock)
...
err := bar()
if err != nil {
return
}
...
// point B - need to unlock here
unlockOnce.Do(lock.Unlock)
}
如果可能,最好重构您的代码,以便锁定的部分保留在单个函数中:
func fooLock() error {
lock.Lock()
defer lock.Unlock()
if err := bar(); err != nil { return err }
...
return nil
}
func foo() {
if err := fooLock(); err != nil { return }
... do the bit that doesn't need a lock
}
显然这里的命名和错误处理是松散的,因为代码是通用的而不是特定的。如果您需要点 B 之前的代码块中的信息(现在位于 fooLock
中的代码中),它可以与错误一起返回。