为了账号安全,请及时绑定邮箱和手机立即绑定

去信号处理

去信号处理

Go
慕的地8271018 2021-06-09 07:24:26
我对 Go 很陌生,并且一直在试图弄清楚如何处理需要返回主循环的事件。在 C 中,我可以只返回函数,但似乎我不能在这里这样做,至少用那个方法是这样。我可以处理需要在 sigHandler() 中处理的信号,即 SIGINT 或 SIGTERM 但我需要在处理 SIGHUP 或 SIGUSR 时将调用返回到 main。在我下面的代码中,一旦我发送挂断信号,进程就会陷入等待模式。如果有人可以帮助我指导我如何正确设计信号处理以处理需要返回到第一个 goroutine 中的主代码的调用,我将不胜感激。编辑我现在在 select{} 中的主 goroutine 中处理通道消息,但是当我发送 HUP 信号时,下面的代码退出。这里的目标是重新加载配置并继续正常执行。在主线代码中,我有这个:go sigHandler()cs := make(chan bool, 1)go sigHandler(cs)// setup the http servererr := setupServer(addr, port)if err != nil {    fatal("Error setting up listening sockets")    os.Exit(1)}    select {    case quit := <-cs:        if quit {            logEvent(loginfo, sys, "Terminating..")            closeLog()            os.Exit(0)        } else {            logEvent(loginfo, sys, "Reloading configuration..")            }    }函数 sigHandler()func sigHandler(cs chan bool) {    c := make(chan os.Signal, 1)    signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)    signal := <-c    logEvent(lognotice, sys, "Signal received: "+signal.String())    switch signal {    case syscall.SIGINT, syscall.SIGTERM:        cs <- true    case syscall.SIGHUP:            cs <- false    }}
查看完整描述

2 回答

?
噜噜哒

TA贡献1784条经验 获得超7个赞

你可以这样做:


package main


import (

        "os"

        "os/signal"

        "syscall"

)


// We make sigHandler receive a channel on which we will report the value of var quit

func sigHandler(q chan bool) {

        var quit bool


        c := make(chan os.Signal, 1)

        signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)


        // foreach signal received

        for signal := range c {

                //      logEvent(lognotice, sys, "Signal received: "+signal.String())


                switch signal {

                case syscall.SIGINT, syscall.SIGTERM:

                        quit = true

                case syscall.SIGHUP:

                        quit = false

                }


                if quit {

                        quit = false

                        //              closeDb()

                        //              logEvent(loginfo, sys, "Terminating..")

                        //              closeLog()

                        os.Exit(0)

                }

                // report the value of quit via the channel

                q <- quit

        }

}


func main() {

        // init two channels, one for the signals, one for the main loop

        sig := make(chan bool)

        loop := make(chan error)


        // start the signal monitoring routine

        go sigHandler(sig)



        // while vat quit is false, we keep going

        for quit := false; !quit; {

                // we start the main loop code in a goroutine

                go func() {

                        // Main loop code here

                        // we can report the error via the chan (here, nil)

                        loop <- nil

                }()


                // We block until either a signal is received or the main code finished

                select {

                // if signal, we affect quit and continue with the loop

                case quit = <-sig:

                // if no signal, we simply continue with the loop

                case <-loop:

                }

        }

}

但是请注意,该信号会导致主循环继续,但不会停止在第一个 goroutine 上的执行。


查看完整回答
反对 回复 2021-06-28
?
慕雪6442864

TA贡献1812条经验 获得超5个赞

这是一种结构化事物来做你想做的事情的方法,分离关注点,这样信号处理代码和主代码是分开的,并且很容易独立测试。


如何实现 Quit 和 ReloadConfig 完全取决于您的程序 - ReloadConfig 可能会在通道上向正在运行的 goroutine 发送“请重新加载”值;它可能会锁定互斥锁并更改一些共享配置数据;或其他一些可能性。


package main


import (

    "log"

    "os"

    "os/signal"

    "syscall"

)


func main() {

    obj := &myObject{}

    go handleSignals(obj)

    select {}

}


type myObject struct {

}


func (obj *myObject) Quit() {

    log.Printf("quitting")

    os.Exit(0)

}


func (obj *myObject) ReloadConfig() {

    log.Printf("reloading configuration")

}


type MainObject interface {

    ReloadConfig()

    Quit()

}


func handleSignals(main MainObject) {

    c := make(chan os.Signal, 1)

    signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)

    for sig := range c {

        switch sig {

        case syscall.SIGINT, syscall.SIGTERM:

            main.Quit()

            return

        case syscall.SIGHUP:

            main.ReloadConfig()

        }

    }

}


查看完整回答
反对 回复 2021-06-28
  • 2 回答
  • 0 关注
  • 161 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信