Browse Source

Merge pull request #82 from yilinershi/master

修复时间轮无法通过CancelTimer方法删除Timer的bug
master
刘丹冰 4 years ago
committed by GitHub
parent
commit
cf3141eadd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      ztimer/timerscheduler.go
  2. 16
      ztimer/timerscheduler_test.go

30
ztimer/timerscheduler.go

@ -31,6 +31,8 @@ type TimerScheduler struct {
triggerChan chan *DelayFunc triggerChan chan *DelayFunc
//互斥锁 //互斥锁
sync.RWMutex sync.RWMutex
//所有注册的timerId集合
ids []uint32
} }
/* /*
@ -59,6 +61,7 @@ func NewTimerScheduler() *TimerScheduler {
return &TimerScheduler{ return &TimerScheduler{
tw: hour_tw, tw: hour_tw,
triggerChan: make(chan *DelayFunc, MAX_CHAN_BUFF), triggerChan: make(chan *DelayFunc, MAX_CHAN_BUFF),
ids: make([]uint32, 0),
} }
} }
@ -68,6 +71,7 @@ func (this *TimerScheduler) CreateTimerAt(df *DelayFunc, unixNano int64) (uint32
defer this.Unlock() defer this.Unlock()
this.idGen++ this.idGen++
this.ids = append(this.ids, this.idGen)
return this.idGen, this.tw.AddTimer(this.idGen, NewTimerAt(df, unixNano)) return this.idGen, this.tw.AddTimer(this.idGen, NewTimerAt(df, unixNano))
} }
@ -77,6 +81,7 @@ func (this *TimerScheduler) CreateTimerAfter(df *DelayFunc, duration time.Durati
defer this.Unlock() defer this.Unlock()
this.idGen++ this.idGen++
this.ids = append(this.ids, this.idGen)
return this.idGen, this.tw.AddTimer(this.idGen, NewTimerAfter(df, duration)) return this.idGen, this.tw.AddTimer(this.idGen, NewTimerAfter(df, duration))
} }
@ -84,8 +89,15 @@ func (this *TimerScheduler) CreateTimerAfter(df *DelayFunc, duration time.Durati
func (this *TimerScheduler) CancelTimer(tid uint32) { func (this *TimerScheduler) CancelTimer(tid uint32) {
this.Lock() this.Lock()
this.Unlock() this.Unlock()
this.tw.RemoveTimer(tid)
//this.tw.RemoveTimer(tid) 这个方法无效
//删除timerId
var index = 0
for i := 0; i < len(this.ids); i++ {
if this.ids[i] == tid {
index = i
}
}
this.ids = append(this.ids[:index], this.ids[index+1:]...)
} }
//获取计时结束的延迟执行函数通道 //获取计时结束的延迟执行函数通道
@ -93,6 +105,15 @@ func (this *TimerScheduler) GetTriggerChan() chan *DelayFunc {
return this.triggerChan return this.triggerChan
} }
func (this *TimerScheduler) HasTimer(tid uint32) bool {
for i := 0; i < len(this.ids); i++ {
if this.ids[i] == tid {
return true
}
}
return false
}
//非阻塞的方式启动timerSchedule //非阻塞的方式启动timerSchedule
func (this *TimerScheduler) Start() { func (this *TimerScheduler) Start() {
go func() { go func() {
@ -101,15 +122,16 @@ func (this *TimerScheduler) Start() {
now := UnixMilli() now := UnixMilli()
//获取最近MAX_TIME_DELAY 毫秒的超时定时器集合 //获取最近MAX_TIME_DELAY 毫秒的超时定时器集合
timerList := this.tw.GetTimerWithIn(MAX_TIME_DELAY * time.Millisecond) timerList := this.tw.GetTimerWithIn(MAX_TIME_DELAY * time.Millisecond)
for _, timer := range timerList {
for tid, timer := range timerList {
if math.Abs(float64(now-timer.unixts)) > MAX_TIME_DELAY { if math.Abs(float64(now-timer.unixts)) > MAX_TIME_DELAY {
//已经超时的定时器,报警 //已经超时的定时器,报警
zlog.Error("want call at ", timer.unixts, "; real call at", now, "; delay ", now-timer.unixts) zlog.Error("want call at ", timer.unixts, "; real call at", now, "; delay ", now-timer.unixts)
} }
if this.HasTimer(tid) {
//将超时触发函数写入管道 //将超时触发函数写入管道
this.triggerChan <- timer.delayFunc this.triggerChan <- timer.delayFunc
} }
}
time.Sleep(MAX_TIME_DELAY / 2 * time.Millisecond) time.Sleep(MAX_TIME_DELAY / 2 * time.Millisecond)
} }
}() }()

16
ztimer/timerscheduler_test.go

@ -10,6 +10,7 @@ package ztimer
import ( import (
"fmt" "fmt"
"github.com/aceld/zinx/zlog" "github.com/aceld/zinx/zlog"
"log"
"testing" "testing"
"time" "time"
) )
@ -63,3 +64,18 @@ func TestNewAutoExecTimerScheduler(t *testing.T) {
//阻塞等待 //阻塞等待
select {} select {}
} }
//测试取消一个定时器
func TestCancelTimerScheduler(t *testing.T) {
Scheduler := NewAutoExecTimerScheduler()
f1 := NewDelayFunc(foo, []interface{}{3, 3})
f2 := NewDelayFunc(foo, []interface{}{5, 5})
timerId1,_:=Scheduler.CreateTimerAfter(f1, time.Duration(3)*time.Second)
timerId2,_:=Scheduler.CreateTimerAfter(f2, time.Duration(5)*time.Second)
log.Printf("timerId1=%d ,timerId2=%d\n",timerId1,timerId2)
Scheduler.CancelTimer(timerId1) //删除timerId1
//阻塞等待
select {}
}
Loading…
Cancel
Save