package main
import (
"os"
"time"
"errors"
"os/signal"
"log"
)
type Runner struct {
interrupt chan os.Signal //操作系统信号
complete chan error // 运行完成时返回信息
timeout <-chan time.Time // 超时单向通道
tasks []func(int) // 存储方法切片
}
//超时返回信息
var ErrTimeout = errors.New("received timeout")
//系统中终止返回信息
var ErrInterrupt = errors.New("received Interrupt")
//Runner生成方法
// os.Signal 系统信息接口
// func After(d Duration) <-chan Time After会在另一线程经过时间段d后向返回值发送当时的时间
func New(d time.Duration) *Runner {
return &Runner{
interrupt: make(chan os.Signal, 1),
complete: make(chan error),
timeout: time.After(d),
}
}
//向runner中添加需要运行的方法
func (r *Runner) Add(tasks ...func(int)) {
r.tasks = append(r.tasks, tasks...)
}
//执行添加的每一个任务
func (r *Runner) run() error {
for id, task := range r.tasks {
if r.gotInterrupt() {
return ErrInterrupt
}
task(id)
}
return nil
}
//验证是否收到系统中断信号
func (r *Runner) gotInterrupt() bool {
select {
case <-r.interrupt:
signal.Stop(r.interrupt)
return true
default:
return false
}
}
// 执行所有任务,监听通道
// func Notify(c chan<- os.Signal, sig ...os.Signal)
// Notify函数让signal包将输入信号转发到c。如果没有列出要传递的信号,会将所有输入信号传递到c;否则只传递列出的输入信号。
func (r *Runner) Start() error {
signal.Notify(r.interrupt, os.Interrupt)
go func() {
r.complete <- r.run()
}()
select {
case err := <-r.complete:
return err
case <-r.timeout:
return ErrTimeout
}
}
const timeout = 3 * time.Second
func main() {
log.Println("starting work")
r := New(timeout)
r.Add(createWork(), createWork(), createWork(), createWork(), createWork(), createWork())
if err := r.Start(); err != nil {
switch err {
case ErrInterrupt:
log.Println("Terminating due to interrupt")
os.Exit(1)
case ErrTimeout:
log.Println("Terminating due to timeout")
os.Exit(2)
}
}
log.Println("run end!")
}
func createWork() func(int) {
return func(d int) {
log.Printf("work: %d start", d)
time.Sleep(time.Duration(d) * time.Second)
log.Printf("work %d end", d)
}
}