Skip to content

time: document proper usage of Timer.Stop #14383

Closed
@anacrolix

Description

@anacrolix

After calling Timer.Stop(), and then clearing the channel, the channel can later be filled anyway. Presumably the task to send to the Timer channel has been put on a run queue, and isn't remove when Stop is called. Here's a test that demonstrates it:

func TestTimerFiresAfterStop(t *testing.T) {
    fail := make(chan struct{})
    done := make(chan struct{})
    defer close(done)
    for range iter.N(1000) {
        tr := time.NewTimer(0)
        tr.Stop()
        // There may or may not be a value in the channel now. But definitely
        // one should not be added after we receive it.
        select {
        case <-tr.C:
        default:
        }
        // Now set the timer to trigger in hour. It definitely shouldn't be
        // receivable now for an hour.
        tr.Reset(time.Hour)
        go func() {
            select {
            case <-tr.C:
                // As soon as the channel receives, notify failure.
                fail <- struct{}{}
            case <-done:
            }
        }()
    }
    select {
    case <-fail:
        t.FailNow()
    case <-time.After(time.Second):
    }
}

Increase the value in iter.N if it doesn't trigger on your system initially. Note that it isn't even necessary to call Reset() to trigger this. You can remove that line. You can Stop() a timer, and then still receive a value from it, some time after you drain it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DocumentationIssues describing a change to documentation.NeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions