Golang pause a loop in a goroutine with channels

William Poussier picture William Poussier · Aug 6, 2016 · Viewed 8.3k times · Source

I have a function that is launched as a goroutine:

func (bt *BlinkyTape) finiteLoop(frames []Frame, repeat int, delay time.Duration) {
    bt.isPlaying = true
L:
    for i := 0; i < repeat; i++ {
        select {
        case <-bt.stop:
            break L
        default:
            bt.playFrames(frames, delay)
        }
    }
    bt.isPlaying = false
}

This function uses channels so it is possible to break the loop (loop can be finite or infinite)

What I would like to implement is a way to pause the execution of the loop and of course being able to resume it.

I was thinking to add another case to the select condition where I listen on another channel pause. If the case is executed, it enter in a new infinite loop that does nothing. Then it will need the same system as previously with a resume channel to break this loop.

What do you think ? Is there a better way to achieve what I need ?

Regards

Answer

user6169399 picture user6169399 · Aug 6, 2016

Pause a loop in a goroutine with channels, use play, pause and quit channels like this working sample code:

package main

import "fmt"
import "time"
import "sync"

func routine() {
    for {
        select {
        case <-pause:
            fmt.Println("pause")
            select {
            case <-play:
                fmt.Println("play")
            case <-quit:
                wg.Done()
                return
            }
        case <-quit:
            wg.Done()
            return
        default:
            work()
        }
    }
}

func main() {
    wg.Add(1)
    go routine()

    time.Sleep(1 * time.Second)
    pause <- struct{}{}

    time.Sleep(1 * time.Second)
    play <- struct{}{}

    time.Sleep(1 * time.Second)
    pause <- struct{}{}

    time.Sleep(1 * time.Second)
    play <- struct{}{}

    time.Sleep(1 * time.Second)
    close(quit)

    wg.Wait()
    fmt.Println("done")
}

func work() {
    time.Sleep(250 * time.Millisecond)
    i++
    fmt.Println(i)
}

var play = make(chan struct{})
var pause = make(chan struct{})
var quit = make(chan struct{})
var wg sync.WaitGroup
var i = 0

output:

1
2
3
4
pause
play
5
6
7
8
pause
play
9
10
11
12
done