# A Go select Bug That Repeatedly Launches a Goroutine After an Interrupt

DevFeed: [A Go select Bug That Repeatedly Launches a Goroutine After an Interrupt](<https://devfeed.tech/articles/my-channel-select-bug-22081.md>)

Original publisher: [Read original article](<https://www.ardanlabs.com/blog/2013/10/my-channel-select-bug.html>)

Published: 2013-10-17T00:00:00Z

Content type: tutorial

Language: en

Sources: [William Kennedy](<https://devfeed.tech/sources/william-kennedy.md>)

Topics: [bug](<https://devfeed.tech/topics/bug.md>), [Go Language](<https://devfeed.tech/topics/go-language.md>), [race-condition](<https://devfeed.tech/topics/race-condition.md>), [Operating system](<https://devfeed.tech/topics/operating-system.md>), [Command-line interface](<https://devfeed.tech/topics/cli.md>)

Tags: [ardan-labs](<https://devfeed.tech/tags/ardan-labs.md>), [blog](<https://devfeed.tech/tags/blog.md>), [bug](<https://devfeed.tech/tags/bug.md>), [code](<https://devfeed.tech/tags/code.md>), [go](<https://devfeed.tech/tags/go.md>), [go-programming](<https://devfeed.tech/tags/go-programming.md>), [golang](<https://devfeed.tech/tags/golang.md>), [os](<https://devfeed.tech/tags/os.md>), [programming](<https://devfeed.tech/tags/programming.md>), [race-condition](<https://devfeed.tech/tags/race-condition.md>), [terminal](<https://devfeed.tech/tags/terminal.md>)

## AI overview

This Go tutorial examines a select statement whose case expression launches a goroutine. After an interrupt, the loop continues and evaluates that expression again, launching the worker repeatedly. The article also identifies a separate race condition involving the shutdown flag.

## Source excerpt

I was testing new functionality on a program that is already running in production when suddenly the code behaved very badly. What I saw shocked me and then it became obvious why it happened. I also have a race condition just waiting to be a problem. I have tried to provide a simplified version of the code and the two bugs. package main import ( "fmt" "os" "os/signal" "time" ) var Shutdown bool = false func main() { sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt) for { select { case <-sigChan: Shutdown = true continue case <-func() chan struct{} { complete := make(chan struct{}) go LaunchProcessor(complete) return complete }(): return } } } func LaunchProcessor(complete chan struct{}) { defer func() { close(complete) }() fmt.Printf("Start Work\n") for count := 0; count < 5; count++ { fmt.Printf("Doing Work\n") time.Sleep(1 * time.Second) if Shutdown == true { fmt.Printf("Kill Early\n") return } } fmt.Printf("End Work\n") } The idea behind this code is to run a task and terminate. It allows the operating system to request the program to terminate early. I always like shutting down the program cleanly when possible. The sample code creates a channel that is bound to an operating system signal and looks for <ctrl> C from the terminal window. If <ctrl> C is issued, the Shutdown flag is set to true and the program continues back into the select statement. The code also spawns a Go routine that performs the work. That routine checks the Shutdown flag to determine if the program needs to terminate early. Bug Number 1 Take a look at this part of the code: case <-func() chan struct{} { complete := make(chan struct{}) go LaunchProcessor(complete) return complete }(): I thought I was being so clever when I wrote this code. I thought it would be cool to execute a function on the fly to spawn the Go routine. It returns a channel that the select waits on to be told the work is complete. When the Go routine is done it closes the channel and the program term