首页 文章

我应该以什么顺序发送信号以正常关闭进程?

提问于
浏览
71

评论者说,在另一个questioncomment上,评论者说:

除非绝对必要,否则不要使用kill -9!无法捕获SIGKILL,因此被杀死的程序无法运行任何关闭例程 . 擦除临时文件 . 首先尝试HUP(1),然后是INT(2),然后是QUIT(3)

我原则上同意 SIGKILL ,但其余的对我来说都是新闻 . 鉴于 kill 发送的默认信号是 SIGTERM ,我预计它是任意进程正常关闭的最常见信号 . 此外,我已经看到 SIGHUP 用于非终止原因,例如告诉守护程序"re-read your config file."而且在我看来 SIGINT (同样的中断你应该得到广泛的支持,或者非常不合适地终止 . )

鉴于 SIGKILL 是最后的手段 - Which signals, and in what order ,您是否应该发送任意进程,以便尽可能优雅地关闭它?

如果可以,请用支持事实(超出个人喜好或意见)或参考资料来证实您的答案 .

注意:我对包括考虑bash / Cygwin的最佳实践特别感兴趣 .

Edit: 到目前为止,似乎没有人提到INT或QUIT,而且HUP的提及有限 . 有没有理由将这些包含在有序的过程中?

7 回答

  • 3

    SIGTERM tells an application to terminate. 其他信号告诉应用程序其他与关闭无关但有时可能具有相同结果的信号 . 唐't use those. If you want an application to shut down, tell it to. Don'吨给它误导信号 .

    有些人认为终止进程的智能标准方法是向其发送大量信号,例如HUP,INT,TERM,最后是KILL . 这是荒唐的 . 正确的终止信号是SIGTERM,如果SIGTERM没有立即终止该过程,那么这是因为应用程序选择处理信号 . 这意味着它有一个很好的理由不立即终止:它有清理工作要做 . 如果你用其他信号中断清理工作,就不知道它还没有保存到磁盘中的内存数据是什么,客户端应用程序是悬挂的,或者你是否正在中断它“中间句子”,这实际上是数据损坏 .

    有关信号真正含义的更多信息,请参阅sigaction(2) . 不要将“默认操作”与“描述”混淆,它们不是一回事 .

    SIGINT用于表示进程的交互式“键盘中断” . 一些程序可以以特殊方式处理该情况以用于终端用户 .

    SIGHUP用于表示终端已消失且不再查看该过程 . 就这些 . 有些进程选择关闭以进行响应,通常是因为没有终端它们的操作没有意义,有些进程选择执行其他操作,例如重新检查配置文件 .

    SIGKILL用于从内核强制删除进程 . 它在某种意义上是特殊的,它实际上并不是进程的信号,而是由内核直接解释 .

    Don't send SIGKILL. SIGKILL肯定不会被脚本发送 . 如果应用程序处理SIGTERM,它可能需要一秒钟来清理,它可能需要一分钟, it can take an hour . 取决于应用程序在准备结束之前必须完成的工作 . 任何“假设”应用程序的清理序列的逻辑已经花了足够长的时间并且需要在X秒之后是快捷方式或SIGKILLed是 just plain wrong .

    应用程序需要SIGKILL终止的唯一原因是,如果在清理序列期间出现问题 . 在这种情况下,您可以手动打开终端和SIGKILL . 除此之外,为什么你要SIGKILL的另一个原因是因为你想要防止它自己清理 .

    即使世界上一半的人在5秒后盲目地发送SIGKILL,但仍然是非常错误的事情 .

  • 87

    通常你会发送 SIGTERM ,默认为kill . 这是默认的原因 . 只有当程序在合理的时间内没有关闭时才应该使用 SIGKILL . 但请注意,对于 SIGKILL ,该程序无法清理数据,数据可能会被破坏 .

    至于 SIGHUPHUP 代表"hang up",历史上意味着调制解调器断开连接 . 它基本上相当于 SIGTERM . 守护进程有时使用 SIGHUP 来重新启动或重新加载配置的原因是守护进程从任何控制终端分离,因为守护进程不需要那些,因此永远不会收到 SIGHUP ,因此该信号被视为"freed up"用于一般用途 . 并非所有守护进程都使用它来重新加载! SIGHUP的默认操作是终止,许多守护进程就是这样做的!因此,你不能盲目地将 SIGHUP 发送给守护进程并期望它们能够存活下来 .

    Edit: SIGINT 可能不适合终止进程,因为它通常与 ^C 或终端设置中断程序无关 . 许多程序都是为了自己的目的捕获它,因此它不常用 . SIGQUIT 通常具有创建核心转储的默认值,除非您希望核心文件存在于其周围,否则也不是一个好的候选者 .

    摘要:如果您发送 SIGTERM 且程序未在您的时间范围内死亡,则发送它 SIGKILL .

  • 6

    Short Answer :发送 SIGTERM ,30秒后, SIGKILL . 也就是说,发送 SIGTERM ,等一下(程序可能会有所不同,你可能会更好地了解你的系统,但是5到30秒就足够了 . 当关闭机器时,你可能会看到它自动等待1到30秒毕竟为什么匆匆?),然后发送 SIGKILL .

    Reasonable AnswerSIGTERMSIGINTSIGKILL 这已经足够了 . 该过程将 very 可能在 SIGKILL 之前终止 .

    Long AnswerSIGTERMSIGINTSIGQUITSIGABRTSIGKILL

    这是不必要的,但至少你不会误导有关你的信息的过程 . 所有这些信号都意味着您希望流程停止正在执行的操作并退出 .

    无论您从这个解释中选择什么答案,请记住这一点!

    如果您发送的信号意味着其他信息,则该过程可能会以非常不同的方式处理(一方面) . 另一方面,如果进程没有处理信号,那么你发送的内容并不重要,无论如何都会退出进程(当然,当默认动作终止时) .

    所以,你必须将自己视为程序员 . 你会编写一个函数处理程序,比方说, SIGHUP 退出一个与某个东西连接的程序,或者你会循环它以尝试再次连接?这是主要问题!这就是为什么发送意味着你想要的信号很重要的原因 .

    Almost Stupid Long Answer

    下表包含相关信号,以及程序未处理时的默认操作 .

    我按照我建议使用的顺序订购它们(顺便说一句,我建议你使用合理的答案,而不是这里的这个),如果你真的需要全部尝试它们(说这个表是按顺序排列会很有趣他们可能造成的破坏,但这并非完全正确) .

    带星号(*)的信号推荐为 NOT . 关于这些的重要一点是你可能永远不知道它的编程是做什么的 . 特别 SIGUSR !它可以启动apocalipse(这是程序员做任何他/她想做的免费信号!) . 但是,如果不处理 OR 在不太可能的情况下处理终止,程序将终止 .

    在表中,具有终止和生成核心转储的默认选项的信号最后留在 SIGKILL 之前 .

    Signal     Value     Action   Comment
    ----------------------------------------------------------------------
    SIGTERM      15       Term    Termination signal
    SIGINT        2       Term    Famous CONTROL+C interrupt from keyboard
    SIGHUP        1       Term    Disconnected terminal or parent died
    SIGPIPE      13       Term    Broken pipe
    SIGALRM(*)   14       Term    Timer signal from alarm
    SIGUSR2(*)   12       Term    User-defined signal 2
    SIGUSR1(*)   10       Term    User-defined signal 1
    SIGQUIT       3       Core    CONTRL+\ or quit from keyboard
    SIGABRT       6       Core    Abort signal from abort(3)
    SIGSEGV      11       Core    Invalid memory reference
    SIGILL        4       Core    Illegal Instruction
    SIGFPE        8       Core    Floating point exception
    SIGKILL       9       Term    Kill signal
    

    然后我会建议这个几乎愚蠢的长答案: SIGTERMSIGINTSIGHUPSIGPIPESIGQUITSIGABRTSIGKILL

    最后,

    Definitely Stupid Long Long Answer

    不要在家尝试这个 .

    SIGTERMSIGINTSIGHUPSIGPIPESIGALRMSIGUSR2SIGUSR1SIGQUITSIGABRTSIGSEGVSIGILLSIGFPE 如果什么都不起作用, SIGKILL .

    SIGUSR2 应该在 SIGUSR1 之前尝试,因为如果程序不处理信号我们会更好 . 如果只处理其中一个,它更有可能处理 SIGUSR1 .

    BTW, the KILL :将 SIGKILL 发送到进程并没有错,正如其他答案所述 . 那么,想想发送 shutdown 命令会发生什么?它只会尝试 SIGTERMSIGKILL . 为什么你认为是这样的?如果非常 shutdown 命令只使用这两个信号,为什么还需要其他信号呢?


    现在,回到 long answer ,这是一个很好的oneliner:

    for SIG in 15 2 3 6 9 ; do echo $SIG ; echo kill -$SIG $PID || break ; sleep 30 ; done
    

    它在信号之间休眠30秒 . 为什么还需要一个oneliner? ;)

    此外,建议:仅使用 reasonable answer 中的信号 15 2 9 进行尝试 .

    安全:当你准备好时,删除第二个 echo . 我把它称为我的 dry-run for onliners . 总是用它来测试 .


    Script killgracefully

    实际上我对这个问题很感兴趣,于是我决定创建一个小脚本来做到这一点 . 请随意下载(克隆)它:

    GitHub链接到Killgracefully repository

  • 5

    SIGTERM 实际上意味着向应用程序发送一条消息:“你会这么善良并自杀” . 它可以被应用程序捕获和处理,以运行清理和关闭代码 .

    SIGKILL 不能被应用程序捕获 . 应用程序被OS杀死,没有任何清理机会 .

    通常首先发送 SIGTERM ,睡一段时间,然后发送 SIGKILL .

  • 6
    • SIGTERM相当于窗口中的"clicking the 'X' " .

    • SIGTERM是Linux在关闭时首先使用的 .

  • 0

    HUP对我来说听起来像垃圾 . 我发送它来获取守护进程重新读取其配置 .

    SIGTERM可以截获;您的守护进程可能会在收到该信号时运行清理代码 . 你不能为SIGKILL做到这一点 . 因此,使用SIGKILL,您不会给守护程序的作者任何选项 .

    更多关于Wikipedia

  • 0

    随着所有讨论在这里进行,没有提供任何代码 . 这是我的看法:

    #!/bin/bash
    
    $pid = 1234
    
    echo "Killing process $pid..."
    kill $pid
    
    waitAttempts=30 
    for i in $(seq 1 $waitAttempts)
    do
        echo "Checking if process is alive (attempt #$i / $waitAttempts)..."
        sleep 1
    
        if ps -p $pid > /dev/null
        then
            echo "Process $pid is still running"
        else
            echo "Process $pid has shut down successfully"
            break
        fi
    done
    
    if ps -p $pid > /dev/null
    then
        echo "Could not shut down process $pid gracefully - killing it forcibly..."
        kill -SIGKILL $pid
    fi
    

相关问题