What would the appropriate design pattern to avoid deadlock when several functions use the same mutex ?
It is quite easy to forget what method uses the lock and so it happens that you call a function that do a mutex.Lock()
inside a function that already locked the mutex --> deadlock.
For example in the following code, it is not explicit right away that the setToNextEvenNb()
is a deadlock. You have to look in nested functions. And it would be even worse if the Lock was in function called 2 or 3 level behind the setToNextEvenNb()
.
package main
import (
"fmt"
"sync"
)
type data struct {
value int
mutex sync.RWMutex
}
func (d *data) isEven() bool {
d.mutex.RLock()
defer d.mutex.RUnlock()
return d.value%2 == 0
}
func (d *data) setToNextEvenNb() {
d.mutex.Lock()
defer d.mutex.Unlock()
if d.isEven() {
d.value += 2
}
d.value += 1
}
func (d *data) set(value int) {
d.mutex.Lock()
defer d.mutex.Unlock()
d.value = value
}
func main() {
var d data
d.set(10)
fmt.Println("data", d.value)
fmt.Println("is even ?", d.isEven())
d.setToNextEvenNb()
fmt.Println("data", d.value)
}
When you have a large code base, this can happen quite easily. I feel that there should be a design pattern to avoid this sort of scenario and I was looking for any advice on this ?
Aucun commentaire:
Enregistrer un commentaire