Terry-Mao / goim

goim
https://goim.io/
MIT License
7.21k stars 1.78k forks source link

timer重复删除TimerData的问题 #98

Closed zhaoyao closed 8 years ago

zhaoyao commented 8 years ago

Hi, 我在自己的项目中借用了goim的timer实现 :), 使用过程中发现了一个问题: 当前的timer实现是检测不到某个TimerData已经被Del过,在以下场景中会导致死循环。


    tmr := NewTimer(100)

    t1 := tmr.Add(time.Second, "test_1", func() {
        fmt.Println("test_1")
    })

    println(t1)
    println(tmr.free)
    println(tmr.free.next)

    tmr.Del(t1)
    println(tmr.free)
    println(tmr.free.next)

    tmr.Del(t1)
    println(tmr.free) // 由于Del中会将 td 设置为free,在这时,timer中的free 和 free.next 发生了循环引用
    println(tmr.free.next)

    t2 := tmr.Add(time.Second, "test_2", func() {
        fmt.Println("test_2")
    })

    t3 := tmr.Add(3*time.Second, "test_3", func() {
        fmt.Println("test_3")
    })
    println(t2)
    println(t3) // 由于t2过期后会将index置为-1, t3过期删除自己时,会因为检测到已过期而跳过从`timers`中删除的步骤导致 t3 被反复执行

    time.Sleep(1 * time.Hour)

具体是在

https://github.com/Terry-Mao/goim/blob/master/libs/time/timer.go#L94

func (t *Timer) put(td *TimerData) {
    td.next = t.free  // 如果 td == t.free , 这里会导致 `timers` 中出现重复的`TimerData`指针
    t.free = td
}

刚刚定位到问题,还没写fix 😆

Terry-Mao commented 8 years ago

目前确实存在这个问题,不过代码基本上都是保证只允许删一次,删两次应该直接panic了,我觉得可以加一个判断,能否提供一个patch,panic 就行了,我觉得