大家对于golang10以及11中对timer.reset的非线程安全抛出怎么看?

mlzhou · 2018-09-01 10:02:31 · 1343 次点击
package main

import (
    "fmt"
    "time"
)

type BaseTimeTest struct {
    conTimer   *time.Timer
    bufferChan chan uint16
}

func NewBaseTimeTest() *BaseTimeTest {
    this := &BaseTimeTest{}
    this.conTimer = time.NewTimer(time.Duration(3) * time.Second)
    this.bufferChan = make(chan uint16, 10)
    return this
}

//向worker push数据
func (this *BaseTimeTest) PushData(data uint16) {
    if len(this.conTimer.C) > 0 {
        fmt.Println("Timeout New", time.Now().Unix())
        this.conTimer = time.NewTimer(time.Duration(3) * time.Second)
    } else {
        fmt.Println("Reset", time.Now().UnixNano())
        this.conTimer.Reset(time.Duration(3) * time.Second)
    }

    select {
    case this.bufferChan <- data:
        fmt.Println("len:", len(this.bufferChan), " data:", data)

    case tmd := <-this.conTimer.C:
        fmt.Println("len:", len(this.bufferChan), "timeout", tmd.UnixNano())
    }
    //this.conTimer.Stop()
}

func (this *BaseTimeTest) Reset() {
    fmt.Println("--Reset time", time.Now().UnixNano())
    this.conTimer.Reset(time.Duration(3) * time.Second)
}

func main() {
    tIns := NewBaseTimeTest()
    go func() {
        for {
            tIns.PushData(1)
        }
    }()

    go func() {
        for {
            tIns.Reset()
            time.Sleep(time.Duration(2999) * time.Millisecond)
            tIns.Reset()
            time.Sleep(time.Duration(3000) * time.Millisecond)
        }
    }()

    select {}
}

golang 1.9.7表示毫无压力

--Reset time 1536120378691200000 len: 10 timeout 1536120378691200000

image.png

注释上又说reset和t.c的写入竞态,到底是否线程安全?

使用golang 1.10以上版本直接挂,对比time包没啥改变,应该是底层c函数改了。

#4
更多评论

求置顶,求解决!不然没法升级。

#1

超时一般不是这么写么

    select {
        case t:=<-c:
            // do something
        case <-time.After(time.Second*10):
            // time out
    }

你这个怎么是用timer来做的?t.Reset 无论哪个版本都是非线程安全的。

#2