mutex.Lock 在解锁前 returns 的功能
function with mutex.Lock that returns before unlocking
我需要使用互斥量来读取变量,如果变量为 0,则从函数中 return。不过,这会阻止互斥体解锁。
我知道我可以简单地在 return 之前放一个 mutex.Unlock,但它看起来不太好/不正确。
我什至不能在函数的开头做一个 defer mutex.Unlock()
因为后面的代码需要很多时间才能 运行.
有正确的方法吗?
这是例子:
func mutexfunc() {
mutex.Lock()
if variable == 0 {
return
}
mutex.Unlock()
// long execution time (mutex must be unlocked)
}
更新:
这是我更喜欢的解决方案:
var mutex = &sync.Mutex{}
var mutexSensibleVar = 0
func main() {
if withLock(func() bool { return mutexSensibleVar == 1 }) {
fmt.Println("it's true")
} else {
fmt.Println("it's false")
}
fmt.Println("end")
}
func withLock(f func() bool) bool {
mutex.Lock()
defer mutex.Unlock()
return f()
}
如果你不能使用 defer
,这是你不能在这里做的事情,你必须做显而易见的事情:
func mutexfunc() {
mutex.Lock()
if variable == 0 {
mutex.Unlock()
return
}
mutex.Unlock()
// long execution time (mutex must be unlocked)
}
如果互斥量只是为了保护那个变量(也就是说,没有你没有向我们展示的其他代码),你也可以使用 sync/atomic
:
func f() {
if atomic.LoadInt64(&variable) ==0 {
return
}
...
}
您可以将锁定的部分分离到它自己的功能中。
func varIsZero() bool {
mutex.Lock()
defer mutex.Unlock()
return variable == 0
}
func mutexfunc() {
if varIsZero() { return }
...
}
另一种方法是在 mutexfunc
中使用匿名函数而不是完全独立的函数,但这是个人喜好问题。
还要考虑带有“需要解锁”布尔值的(笨拙但可读的)变体:
func f(arg1 argtype1, arg2 argtype2) ret returntype {
var needToUnlock bool
defer func() {
if needToUnlock {
lock.Unlock()
}
}()
// arbitrary amount of code here that runs unlocked
lock.Lock()
needToUnlock = true
// arbitrary amount of code here that runs locked
lock.Unlock()
needToUnlock = false
// arbitrary amount of code here that runs unlocked
// repeat as desired
}
你可以把这样的东西包装成一个类型:
type DeferableLock struct {
L Locker
isLocked bool
}
func (d *DeferableLock) Lock() {
d.L.Lock()
d.isLocked = true
}
func (d *DeferableLock) Unlock() {
d.L.Unlock()
d.isLocked = false
}
func (d *DeferableLock) EnsureUnlocked() {
if d.isLocked {
d.Unlock()
}
}
func NewDeferableLock(l Locker) *DeferableLock() {
return &DeferableLock{L: l}
}
您现在可以用 DeferableLock
包裹任何 sync.Locker
。在像 f
这样的函数中,使用可延迟包装器来包装锁,然后调用 defer d.EnsureUnlock
.
(与 sync.Cond
的任何相似之处完全是故意的。)
我需要使用互斥量来读取变量,如果变量为 0,则从函数中 return。不过,这会阻止互斥体解锁。
我知道我可以简单地在 return 之前放一个 mutex.Unlock,但它看起来不太好/不正确。
我什至不能在函数的开头做一个 defer mutex.Unlock()
因为后面的代码需要很多时间才能 运行.
有正确的方法吗?
这是例子:
func mutexfunc() {
mutex.Lock()
if variable == 0 {
return
}
mutex.Unlock()
// long execution time (mutex must be unlocked)
}
更新:
这是我更喜欢的解决方案:
var mutex = &sync.Mutex{}
var mutexSensibleVar = 0
func main() {
if withLock(func() bool { return mutexSensibleVar == 1 }) {
fmt.Println("it's true")
} else {
fmt.Println("it's false")
}
fmt.Println("end")
}
func withLock(f func() bool) bool {
mutex.Lock()
defer mutex.Unlock()
return f()
}
如果你不能使用 defer
,这是你不能在这里做的事情,你必须做显而易见的事情:
func mutexfunc() {
mutex.Lock()
if variable == 0 {
mutex.Unlock()
return
}
mutex.Unlock()
// long execution time (mutex must be unlocked)
}
如果互斥量只是为了保护那个变量(也就是说,没有你没有向我们展示的其他代码),你也可以使用 sync/atomic
:
func f() {
if atomic.LoadInt64(&variable) ==0 {
return
}
...
}
您可以将锁定的部分分离到它自己的功能中。
func varIsZero() bool {
mutex.Lock()
defer mutex.Unlock()
return variable == 0
}
func mutexfunc() {
if varIsZero() { return }
...
}
另一种方法是在 mutexfunc
中使用匿名函数而不是完全独立的函数,但这是个人喜好问题。
还要考虑带有“需要解锁”布尔值的(笨拙但可读的)变体:
func f(arg1 argtype1, arg2 argtype2) ret returntype {
var needToUnlock bool
defer func() {
if needToUnlock {
lock.Unlock()
}
}()
// arbitrary amount of code here that runs unlocked
lock.Lock()
needToUnlock = true
// arbitrary amount of code here that runs locked
lock.Unlock()
needToUnlock = false
// arbitrary amount of code here that runs unlocked
// repeat as desired
}
你可以把这样的东西包装成一个类型:
type DeferableLock struct {
L Locker
isLocked bool
}
func (d *DeferableLock) Lock() {
d.L.Lock()
d.isLocked = true
}
func (d *DeferableLock) Unlock() {
d.L.Unlock()
d.isLocked = false
}
func (d *DeferableLock) EnsureUnlocked() {
if d.isLocked {
d.Unlock()
}
}
func NewDeferableLock(l Locker) *DeferableLock() {
return &DeferableLock{L: l}
}
您现在可以用 DeferableLock
包裹任何 sync.Locker
。在像 f
这样的函数中,使用可延迟包装器来包装锁,然后调用 defer d.EnsureUnlock
.
(与 sync.Cond
的任何相似之处完全是故意的。)