Strange behavior of for-select statement with terminate signal

whats happening with channel of os.signal ?
i have code in which i have a subscribed to os signal and signal is received on channel. Whats happening is when i do go run example.go and stop the program it is not stopped and doesn’t go into case <- sig and runs default case. signal is passed on channel but case is not running.

package main

import (
	"os"
	"os/signal"
	"syscall"
	"fmt"
	"time"
)

func main()  {
	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
	for   {
		select {
		case <-sig:
			break
		default:
			fmt.Print("default \n")
		time.Sleep(1*time.Millisecond)
			continue
		}
		break
	}
}

but after that what i created a pipeline when signal is received on sig chan is i push value to other channel and that channel’s case runs and loop break.
why os.signal is not giving the same behavior?

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
	pipeline := make(chan int)

	go func(sig chan os.Signal, pipe chan int) {
		<-sig
		pipe <- 1
	}(sig, pipeline)

	for {
		select {
		case <-pipeline:
			break
		default:
			fmt.Print("default \n")
			time.Sleep(1 * time.Millisecond)
			continue
		}
		break
	}
}

It uses a non-blocking send, so you need a buffered channel or be sure to be blocking on the read. Currently you’re almost guaranteed to be in the sleep and not waiting for the signal when it comes.

Package signal will not block sending to c: the caller must ensure that c has sufficient buffer space to keep up with the expected signal rate. For a channel used for notification of just one signal value, a buffer of size 1 is sufficient.

(signal package - os/signal - Go Packages)

1 Like

and time.After channel work in the same way right
thanks man now i understand

1 Like