diff --git a/internal/iplibrary/manager_country.go b/internal/iplibrary/manager_country.go index f17e4bd..f75c10e 100644 --- a/internal/iplibrary/manager_country.go +++ b/internal/iplibrary/manager_country.go @@ -63,7 +63,7 @@ func (this *CountryManager) Start() { events.On(events.EventQuit, func() { ticker.Stop() }) - for range ticker.C { + for ticker.Next() { err := this.loop() if err != nil { remotelogs.ErrorObject("COUNTRY_MANAGER", err) diff --git a/internal/iplibrary/manager_province.go b/internal/iplibrary/manager_province.go index 0fa76c5..32ed1d8 100644 --- a/internal/iplibrary/manager_province.go +++ b/internal/iplibrary/manager_province.go @@ -67,7 +67,7 @@ func (this *ProvinceManager) Start() { events.On(events.EventQuit, func() { ticker.Stop() }) - for range ticker.C { + for ticker.Next() { err := this.loop() if err != nil { remotelogs.ErrorObject("PROVINCE_MANAGER", err) diff --git a/internal/utils/ticker.go b/internal/utils/ticker.go index e67e652..7ff6b74 100644 --- a/internal/utils/ticker.go +++ b/internal/utils/ticker.go @@ -1,47 +1,43 @@ package utils import ( + "sync" "time" ) -// 类似于time.Ticker,但能够真正地停止 +// Ticker 类似于time.Ticker,但能够真正地停止 type Ticker struct { - raw *time.Ticker + raw *time.Ticker + done chan bool + once sync.Once - S chan bool C <-chan time.Time - - isStopped bool } -// 创建新Ticker +// NewTicker 创建新Ticker func NewTicker(duration time.Duration) *Ticker { raw := time.NewTicker(duration) return &Ticker{ - raw: raw, - C: raw.C, - S: make(chan bool, 1), + raw: raw, + C: raw.C, + done: make(chan bool, 1), } } -// 查找下一个Tick +// Next 查找下一个Tick func (this *Ticker) Next() bool { select { case <-this.raw.C: return true - case <-this.S: + case <-this.done: return false } } -// 停止 +// Stop 停止 func (this *Ticker) Stop() { - if this.isStopped { - return - } - - this.isStopped = true - - this.raw.Stop() - this.S <- true + this.once.Do(func() { + this.raw.Stop() + this.done <- true + }) } diff --git a/internal/utils/ticker_test.go b/internal/utils/ticker_test.go index 46875c5..0f2e822 100644 --- a/internal/utils/ticker_test.go +++ b/internal/utils/ticker_test.go @@ -41,9 +41,9 @@ func TestTicker2(t *testing.T) { for { t.Log("loop") select { - case <-ticker.C: + case <-ticker.raw.C: t.Log("tick") - case <-ticker.S: + case <-ticker.done: return } } @@ -63,3 +63,17 @@ func TestTickerEvery(t *testing.T) { }) wg.Wait() } + + +func TestTicker_StopTwice(t *testing.T) { + ticker := NewTicker(3 * time.Second) + go func() { + time.Sleep(10 * time.Second) + ticker.Stop() + ticker.Stop() + }() + for ticker.Next() { + t.Log("tick") + } + t.Log("finished") +}