Go语言的坑: String Format 带来的 Dead Lock

Go语言的坑: String Format 带来的 Dead Lock

[toc]

如果类型定义了 String() 方法,它会被用在 fmt.Printf() 中生成默认的输出:等同于使用格式化描述符 %v 产生的输出。还有 fmt.Print() 和 fmt.Println() 也会自动使用 String() 方法。

那么我们看看下面的例子:

type Customer struct {
  mutex sync.RWMutex
  id string
  age int
}

func (c *Customer) UpdateAge(age int) error {
  c.mutex.Lock()
  defer c.mutex.Unlock()

  if age < 0 {
    return fmt.Errorf("age should be positive for customer %v", c)
  }

  c.age = age
  return nil
}

func (c *Customer) String() string {
  fmt.Println("enter string method")
  c.mutex.RLock()
  defer c.mutex.RUnlock()
  return fmt.Sprintf("id %s, age %d", c.id, c.age)}

这个例子中,如果调用 UpdateAge 方法 age 小于0会调用 fmt.Errorf,格式化输出,这个时候 String() 方法里面也进行了加锁,那么这样会造成死锁。

mutex.Lock -> check age -> Format error -> call String() -> mutex.RLock

解决方法也很简单,一个是缩小锁的范围,在 check age 之后再加锁,另一种方法是 Format error 的时候不要 Format 整个结构体,可以改成 Format id 就行了。

Licensed under CC BY-NC-SA 4.0
Built with Hugo
主题 StackJimmy 设计