Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is it possible to stop timer gracefully without additional channel in golang?

Here is my test code:

package main

import (
    "runtime"
    "testing"
    "time"
)

func testTimerRoutine(expire bool) bool {
    dur := 10 * time.Millisecond
    timer := time.NewTimer(dur)
    leak := true
    go func() {
        defer func() {
            println("timer routine quit")
            leak = false
        }()
        <-timer.C
        println("timer expired")
    }()

    if expire {
        time.Sleep(2 * dur)
    }

    if !timer.Stop() {
        println("timer stop false")
        <-timer.C
    } else {
        println("timer stop true")
    }

    runtime.GC()
    time.Sleep(10 * dur)
    return leak
}

func TestTimerRoutineDeadlock(t *testing.T) {
    leak := testTimerRoutine(true)
    if leak {
        t.Errorf("routine leak")
    }
}

func TestTimerRoutineLeak(t *testing.T) {
    leak := testTimerRoutine(false)
    if leak {
        t.Errorf("routine leak")
    }
}

I meant to think that without other channels, just using time.Timer.C.

I now start a go routine dedicated to reading timer.C in response to a timer timeout after the timer is started.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

But I found two problems with this approach:

  1. there seems to be a problem with the go routine not exiting if the timer is stopped before it has timed out;
  2. If the timer has already timed out and the call to Stop() returns false, there will be a deadlock at this point to drain timer.C as required by the API.

I wonder if there is a way, without using an additional Channel, to achieve the functionality I require to stop the timer early in response to a timer timeout.

>Solution :

Here’s a quote from the documentation of timer:

This (Stop) cannot be done concurrent to other receives from the Timer’s channel or other calls to the Timer’s Stop method.

Yet, this is exactly what you are doing. You have a goroutine receiving from a timer channel concurrently with the Stop call.

In general, if you need to stop a timer because of some sort of an event, send a request to the listening goroutine to stop the timer.

You don’t have to drain the channel as it is a channel with capacity 1, so if nothing is listening from it, it will be garbage collected.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading