Обратите внимание, что если вы "установите" свой канал сигнала с signal.Notify()
, поведение по умолчанию будет отключено.Это означает, что если вы сделаете это, цикл for
в вашей функции fn()
не будет прерываться, он будет продолжать работать.
Поэтому, когда вы получаете значение на своем зарегистрированном канале, вы должны сделатьцикл for
завершается, поэтому вы можете выполнить «чистую» очистку.В противном случае ресурсы cleanup()
, которые должны быть освобождены, могут по-прежнему использоваться в for
, что, скорее всего, приведет к ошибке или панике.
После того, как вы это сделаете, вам даже не придется вызывать cleanup()
вручную,потому что возврат из fn()
будет правильно запускать отложенную функцию.
Вот пример:
var shutdownCh = make(chan struct{})
func fn() {
defer cleanup()
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
close(shutdownCh)
}()
for {
select {
case <-shutdownCh:
return
// Other cases might be listed here..
default:
}
time.Sleep(time.Millisecond)
}
}
Конечно, приведенный выше пример не гарантирует завершение приложения.У вас должен быть какой-то код, который слушает shutdownCh
и завершает работу приложения.Этот код также должен ждать, пока все изящные программы завершатся.Для этого вы можете использовать sync.WaitGroup
: добавьте к нему 1, когда вы запускаете программу, которую следует ожидать при выходе, и вызывайте WaitGroup.Done()
, когда такая программа завершится.
Такжепоскольку в реальном приложении их может быть много, обработку сигналов следует перенести в «центральное» место, а не в каждом месте.
Вот полный пример того, как это сделать:
var shutdownCh = make(chan struct{})
var wg = &sync.WaitGroup{}
func main() {
wg.Add(1)
go func() {
defer wg.Done()
fn()
}()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
close(shutdownCh)
wg.Wait()
}
func fn() {
defer cleanup()
for {
select {
case <-shutdownCh:
return
// Other cases might be listed here..
default:
}
fmt.Println("working...")
time.Sleep(time.Second)
}
}
func cleanup() {
fmt.Println("cleaning up...")
}
Вот пример выходных данных вышеуказанного приложения при нажатии CTRL + C через 3 секунды после его запуска:
working...
working...
working...
^Ccleaning up...