Reputation: 47
I need to use mutex to read a variable and if the variable is 0, return from the function. This would prevent the mutex from Unlocking though.
I know that I could simply put a mutex.Unlock just before the return but it does not seem nice / correct.
I can't even do a defer mutex.Unlock()
at the beginning of the function because the the code after requires a lot of time to run.
Is there a correct way to do so?
This is the example:
func mutexfunc() {
mutex.Lock()
if variable == 0 {
return
}
mutex.Unlock()
// long execution time (mutex must be unlocked)
}
UPDATE:
this is the solution I prefer:
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()
}
Upvotes: 1
Views: 1175
Reputation: 487805
Also consider the (clumsy but readable) variant with a "need to unlock" boolean:
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
}
You can wrap such a thing up in a type:
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}
}
You can now wrap any sync.Locker
with a DeferableLock
. At functions like f
, use the deferable wrapper to wrap the lock, and call defer d.EnsureUnlock
.
(Any resemblance to sync.Cond
is entirely deliberate.)
Upvotes: 0
Reputation: 58201
You can separate the locked part into its own function.
func varIsZero() bool {
mutex.Lock()
defer mutex.Unlock()
return variable == 0
}
func mutexfunc() {
if varIsZero() { return }
...
}
An alternative would be to use an anonymous function inside mutexfunc
rather than a completely independent function, but it's a matter of taste here.
Upvotes: 3
Reputation: 51502
If you can't use defer
, which is something you can't do here, you have to do the obvious:
func mutexfunc() {
mutex.Lock()
if variable == 0 {
mutex.Unlock()
return
}
mutex.Unlock()
// long execution time (mutex must be unlocked)
}
If the mutex is there only to protect that variable (that is, there isn't other code you're not showing us), you can also use sync/atomic
:
func f() {
if atomic.LoadInt64(&variable) ==0 {
return
}
...
}
Upvotes: 3