В някои случаи ни е нужно нашите програми да обработват сигнали в
юникс-подобни1 уредби. Например
бихме искали сървърът ни да спира, когато получи сигнал SIGTERM, или наше
приложение за командния ред да спре да обработва входни данни, щом получи сигнал
SIGINT. Ето как да обработваме сигнали в Го с помощта на канали.
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
Уведомлението чрез сигнал в Го работи чрез изпращане на стойности от
вида os.Signal по канал. Ще създадем канал, по който да получаваме
тези уведомления. Забележете, че каналът трябва да е складиращ.
знаци := make(chan os.Signal, 1)
signal.Notify записва дадения канал да получава указаните сигнали като
уведомления.
signal.Notify(знаци, syscall.SIGINT, syscall.SIGTERM)
Бихме могли да получаваме известия по канала знаци дори тук, в
главната функция, но нека видим как това може да бъде направено в
отделна гозадача. Така ще покажем по-близък до действителността случай,
как се прави чисто приключване на програма.
приключване := make(chan bool, 1)
Тази гозадача изпълнява спиращо получаване на сигнали. Когато получи сигнал го отпечатва на стандартния изход, а после уведомява програмата, че може да приключи изпълнението си.
go func() {
sig := <-знаци
fmt.Println()
fmt.Println(sig)
приключване <- true
}()
Тук програмата чака, докато получи очаквания знак (сигнал), както бива
указано от горната гозадача, която изпраща стойност true, щом
променливата приключване (която е също складиращ канал) има стойност,
а после приключва.
fmt.Println("чакам знак")
<-приключване
fmt.Println("излизам")
}
Когато пуснем тази програма, тя спира и чака знак. Като натиснем ctrl-C (в
терминала се вижда като ^C) изпращаме сигнал SIGINT, който кара
програмата да изведе “излизам” и да излезе. “interrupt” е представения като
низ отпечатания от гозадачата SIGINT.
$ go run signals.go
чакам знак
^C
interrupt
излизам
exiting
Следващ пример: Съвременна обработка на сигнали с Context.