SoFunction
Updated on 2025-03-01

Note on the Notify usage of signal package in golang

The function declaration is:

func Notify(c chan<- , sig ...)

Official description:

The Notify function allows the signal packet to forward the input signal to c. If the signal to be passed is not listed, all input signals are passed to c; otherwise only the listed input signals are passed.

The signal packet will not block in order to send information to C (that is, if C blocks when sending, the signal packet will be abandoned directly): the caller should ensure that C has enough cache space to keep up with the expected signal frequency. For channels that use a single signal for notification, a cache of 1 is sufficient.

Sample code:

ch := make(chan , 1)
  (ch, , , , , syscall.SIGUSR1)
  for {
    s := <-ch
    switch s {
    case :
      ("SIGSTOP")
      return
    case :
      ("SIGSTOP")
      return
    case :
      ("SIGHUP")
      return
    case :
      ("SIGKILL")
      return
    case syscall.SIGUSR1:
      ("SIGUSR1")
      return
    default:
      ("default")
      return
    }
  }

The above code tells signal to notify the corresponding signal, and then perform different processing for different signals in the for loop. The for loop is a dead loop.

Additional: About using a channel with cache

package main
import (
  "fmt"
  "os"
  "os/signal"
)
func main() {
  // Set up channel on which to send signal notifications.
  // We must use a buffered channel or risk missing the signal
  // if we're not ready to receive when the signal is sent.
  c := make(chan , 1)
  (c, )
  // Block until a signal is received.
  s := <-c
  ("Got signal:", s)
}

The above code is the example code, and the comment says:

We have to use a buffered channel

Otherwise, when we are sending the signal, we are not ready to receive it, and there is a risk of losing the signal.

I haven't understood this comment yet, so I looked through the source code $GOROOT/src/os/signal/, there is such a piece of code, and the comment has "send but not blocking". This should be the reason why the signal is "possible to be lost".

  ...
  for c, h := range  {
    if (n) {
      // send but do not block for it
      select {
      case c <- sig:
      default:
      }
    }
  }
  ...

So, I wrote a piece of code to test it:

package main
import (
  "log"
  "os"
  "os/signal"
  "time"
)
func main() {
  c := make(chan )
  (c, )
  ( * 5) // Pretend to receive it in 5 seconds  s := &lt;-c
  (s)
}

When using a channel without cache, no matter how many control + c is pressed during the 5-second sleep, the end of sleep will not be printed and the program will not be exited;

When using a cached channel, as long as a SIGINT is received, it will print and exit the program after sleep is completed.

This is what it does to use a cached channel.

The above is personal experience. I hope you can give you a reference and I hope you can support me more. If there are any mistakes or no complete considerations, I would like to give you advice.