cokeboL 发表于 2017-08-16 13:14

如何定位死锁


发个自己常用的库: https://github.com/naivefox/foxmutex

sample:
package main

import (
        "fmt"
        fox "github.com/naivefox/foxmutex"
        "time"
)

func main() {
        fox.SetDebug(true, time.Second)

        mtx := fox.Mutex{}

        fmt.Println(111)
        mtx.Lock()
        fmt.Println(222)

        go func() {
                fmt.Println(333)
                mtx.Lock()
                fmt.Println(444)
        }()

        time.Sleep(time.Hour)
}package main

import (
        "fmt"
        fox "github.com/naivefox/foxmutex"
        "time"
)

func main() {
        fox.SetDebug(true, time.Second)

        mtx := fox.RWMutex{}

        fmt.Println(111)
        mtx.Lock()
        fmt.Println(222)

        go func() {
                fmt.Println(333)
                mtx.RLock()
                fmt.Println(444)
        }()

        time.Sleep(time.Hour)
}

lxyscls 发表于 2017-08-30 13:36

-race?????

cokeboL 发表于 2017-08-30 21:59

回复 2# lxyscls

-race 有用吗?你试下这段代码能用-race解决吗:package main

import (
        "fmt"
        "sync"
        "time"
)

func main() {
        mtx := sync.Mutex{}

        fmt.Println(111)
        mtx.Lock()
        fmt.Println(222)

        go func() {
                fmt.Println(333)
                mtx.Lock()
                fmt.Println(444)
        }()

        time.Sleep(time.Hour)
}


lxyscls 发表于 2017-08-31 09:13

本帖最后由 lxyscls 于 2017-08-31 09:45 编辑

cokeboL 发表于 2017-08-30 21:59
回复 2# lxyscls

-race 有用吗?你试下这段代码能用-race解决吗:
伦家刚把K大爷的书看完,一行代码都没写过呢{:yct57:}

But,你这个代码其实不是死锁呢,1个小时后会解开的{:yct44:}

cokeboL 发表于 2017-08-31 11:07

回复 4# lxyscls

:mrgreen:我功力不够所以只能锁住它一小时,等我功力提升了把它锁time.Hour * 2你先 go get "github.com/naivefox/foxmutex"
然后直接go run 我那个代码就知道效果了:mrgreen:

lxyscls 发表于 2017-08-31 14:38

回复 5# cokeboL

这个求解释

[*]为什么在Mutex.Lock和RWMutex.Lock之后还要起timer?
[*]Lock之前的timer key没有记下来,Unlock只有让它自己超时


另外就是,timer中记录log用到了另外一把锁,应该是防止log混乱的?但是这样我觉得肯定会影响真正被使用的锁的,兴许原来要死锁的,加了debug就不出了,还不如把log都buffer起来,一次性输出,由fmt.println自己去保证。

cokeboL 发表于 2017-08-31 16:02

回复 6# lxyscls

1.因为你Lock()成功获取了锁,但是你很久不释放,可能也是bug,所以也做了超时的log,就比如package main

import (
      "fmt"
      fox "github.com/naivefox/foxmutex"
      "time"
)

func main() {
      fox.SetDebug(true, time.Second)

      mtx := fox.Mutex{}

      fmt.Println(111)
      mtx.Lock()
      fmt.Println(222)

      time.Sleep(time.Hour)
}只调用一次Lock(),通常情况下不会锁住太久
这个库的日志是相当于Warning,具体是不是死锁由写代码的人来根据实际情况判定

cokeboL 发表于 2017-08-31 16:05

回复 6# lxyscls

2. Lock之前的timer key没有记下来,Unlock只有让它自己超时
这句没太看懂。。
我弄两个timer是因为 Lock() 之前的是获取锁失败的超时告警
                            Lock() 之后的是获取锁成功但是超时没释放的告警

cokeboL 发表于 2017-08-31 16:16

本帖最后由 cokeboL 于 2017-08-31 16:18 编辑

回复 6# lxyscls

“另外就是,timer中记录log用到了另外一把锁,应该是防止log混乱的?但是这样我觉得肯定会影响真正被使用的锁的,兴许原来要死锁的,加了debug就不出了,还不如把log都buffer起来,一次性输出,由fmt.println自己去保证。”
用到另一把锁是为了在不同的并行流中Lock()和Unlock()的时候根据自己的id来获取、存储、释放之前的timer,因为timer是放
到 mtxmutexes(这个命名应该改成mtxtimers...,懒得查找替换不打算改了) 这个全局map里,多个并行流,肯定要加锁,
go 1.9的sync包里新增了个Map类型是并发安全的,换成那个就不需要在foxmutex这里用另外一把锁了,但是看了下源码里面
还是map+mutex,感觉鸡肋sync.Map也是个鸡肋:dizzy:

还有就是,这个额外的锁只是在getLockTimer、saveLockTimer、unsaveLockTimer里使用,这几个func里可以保证这个额外
的锁对原本要来debug的锁没有影响

另外就是性能问题,这个包的锁肯定性能不好,但是只作为调试期使用帮助发现问题,我一般这样写:
package main

import (
      "fmt"
      fox "github.com/naivefox/foxmutex"
      "time"
)

type MyMutex struct {
      fox.Mutex //debug
      //sync.Mutex //release
}

/* type MyMutex fox.Mutex 这样不行,好像跟time包里的有关 */

func init() {
      fox.SetDebug(true, time.Second)
}

func main() {
      mtx := MyMutex{}

      fmt.Println(111)
      mtx.Lock()
      fmt.Println(222)

      time.Sleep(time.Hour)
}


dorodaloo 发表于 2017-09-14 14:11

我对于cokeboL老师,都是抱着敬仰的态度。
页: [1] 2
查看完整版本: 如何定位死锁