go - How can this pattern result in a deadlock? -


i have (lru) cache object , encounter deadlock... how possible?

  type cache struct {     mutex *sync.mutex     ...   }    func (this *cache) init() {  // guaranteed called once, in main()     this.mutex = &sync.mutex{}   }    func (this *cache) f1() {      // pattern accessing mute, @ top of function of 'cache' needed.      this.mutex.lock()      defer this.mutex.unlock()      ...   }     func (this *cache) f2() {      this.mutex.lock()      defer this.mutex.unlock()      ...   } 

in every function mutex appears, accessed pattern only. , yet... deadlock. how come possible?

note: code has been running on production server 10 months , first time that.

edit: f1() can call (indirectly) f2() deadlock based on answers. true in code doesn't happen, wonder

deadlock may occur if 1 method of cache calls method, , both contain lock() call.

see example:

func (this *cache) f1() {     this.mutex.lock()     defer this.mutex.unlock()     this.f2() }  func (this *cache) f2() {     this.mutex.lock()     defer this.mutex.unlock() }  func main() {     c := &cache{}     c.init()     c.f1()     fmt.println("hello, playground") } 

output (try on go playground):

fatal error: goroutines asleep - deadlock!  goroutine 1 [semacquire]: sync.runtime_semacquiremutex(0x1040a12c, 0x8)     /usr/local/go/src/runtime/sema.go:62 +0x40 sync.(*mutex).lock(0x1040a128, 0x10429f5c)     /usr/local/go/src/sync/mutex.go:87 +0xa0 main.(*cache).f2(0x10429f94, 0x1100c0)     /tmp/sandbox647646735/main.go:23 +0x40 main.(*cache).f1(0x10429f94, 0xdf6e0)     /tmp/sandbox647646735/main.go:19 +0xa0 main.main()     /tmp/sandbox647646735/main.go:30 +0x60 

note there not need have direct call 1 method other, may transitive call. example cache.f1() may call foo() may "standalone" function, , if foo() calls cache.f2(), we're @ same deadlock.

improvements:

don't name receiver this, not idiomatic. may call c. read more here: in go naming receiver variable 'self' misleading or practice?

you may embed mutexes, making convenient use , eliminate need initialization. read more here: when embed mutex in struct in go?

type cache struct {     sync.mutex }  func (c *cache) f1() {     c.lock()     defer c.unlock()     c.f2() }  func (c *cache) f2() {     c.lock()     defer c.unlock() }  func main() {     c := &cache{}     c.f1()     fmt.println("hello, playground") } 

of course causes deadlock. try on go playground. note inherently exposes mutex (as embedded type starts lowecae letter), able call lock() , unlock() methods. depends on case whether problem.


Comments

Popular posts from this blog

node.js - Node js - Trying to send POST request, but it is not loading javascript content -

javascript - Replicate keyboard event with html button -

javascript - Web audio api 5.1 surround example not working in firefox -