是什么原因导致发送各种信号?

是什么原因导致发送各种信号?

有时我对进程可以接收的所有信号感到有点困惑。据我了解,一个进程有一个默认处理程序(信号处理)对于每个信号,但它可以通过调用提供自己的处理程序sigaction()

所以这是我的问题:是什么导致每个信号被发送?我意识到您可以通过参数-sto手动向正在运行的进程发送信号kill,但是有哪些自然的在什么情况下发送这些信号?例如,什么时候SIGINT发送?

另外,对于可以处理哪些信号有任何限制吗?甚至可以SIGSEGV处理信号并将控制权返回给应用程序吗?

答案1

除了进程调用之外kill(2), 一些信号在各种情况下由内核(或有时由进程本身)发送:

  • 终端驱动程序发送与各种事件相对应的信号:
    • 按键通知: SIGINT(请返回主循环)在Ctrl+上CSIGQUIT(请立即退出) on Ctrl+ \, SIGTSTP(请暂停)Ctrl+ Z。可以使用以下命令更改按键stty命令。
    • SIGTTINSIGTTOU当后台进程尝试读取或写入其控制终端时发送。
    • SIGWINCH发送信号表示终端窗口的大小已更改。
    • SIGHUP发送信号表示终端已消失(历史上因为您的调制解调器已消失)H向上,现在通常是因为您关闭了终端模拟器窗口)。
  • 一些处理器陷阱可以生成信号。细节取决于架构和系统;以下是典型示例:
    • SIGBUS对于未对齐的访问存储器;
    • SIGSEGV用于访问未映射的页面;
    • SIGILL非法指令(错误的操作码);
    • SIGFPE对于带有错误参数的浮点指令(例如sqrt(-1))。
  • 许多信号通知目标进程发生了某些系统事件:
    • SIGALRM通知进程设置的计时器已过期。定时器可以设置为alarm,setitimer和别的。
    • SIGCHLD通知进程其一个子进程已死亡。
    • SIGPIPE当进程在读取端已关闭时尝试写入管道时生成(其想法是,如果您运行foo | barbar退出,foo则会被 a 杀死SIGPIPE)。
    • SIGPOLL(也称为SIGIO)通知进程发生了可轮询事件。 POSIX 指定通过以下方式注册的可轮询事件I_SETSIG ioctl。许多系统允许任何文件描述符上的可轮询事件,通过O_ASYNC fcntl旗帜。相关信号是SIGURG,它通知设备上的紧急数据(通过注册I_SETSIG ioctl) 或者插座
    • 在某些系统上,SIGPWR被发送到所有进程时UPS表示即将停电。

这些列表并不详尽。标准信号定义在signal.h

大多数信号可以被应用程序捕获和处理(或忽略)。唯一无法捕获的两个便携式信号是SIGKILL(就死吧)和STOP(停止执行)。

SIGSEGV分段故障)及其表弟SIGBUS总线错误)可能会被抓住,但这是一个坏主意,除非您真的知道自己在做什么。捕获它们的常见应用是打印堆栈跟踪或其他调试信息。更高级的应用程序是实现某种进程内内存管理,或者捕获虚拟机引擎中的错误指令。

最后,让我提一下不是信号的事情。当您在从终端读取输入的程序中的行开头按Ctrl+D时,这会告诉程序已到达输入文件的末尾。这不是一个信号:它是通过输入/输出 API 传输的。喜欢Ctrl+C和朋友,可以用 来配置按键stty

答案2

首先回答你的第二个问题:SIGSTOPSIGKILL不能被应用程序捕获,但所有其他信号都可以,甚至SIGSEGV.此属性对于调试很有用 - 例如,通过正确的库支持,您可以侦听SIGSEGV并生成堆栈回溯以显示段错误发生的位置。

man 7 signal通过在 Linux 命令行中 键入,可以获得有关每个信号功能的官方说明(无论如何,对于 Linux) 。http://linux.die.net/man/7/signal具有相同的信息,但表格更难以阅读。

然而,如果没有一些信号方面的经验,很难从简短的描述中了解它们在实践中的作用,所以这是我的解释:

从键盘触发

  • SIGINT当你击中 时就会发生CTRL+C
  • SIGQUIT由 触发CTRL+\,并转储核心。
  • SIGTSTP当您点击 时暂停您的程序CTRL+Z。与 不同的是SIGSTOP,它是可捕获的,这使得程序有vi机会在挂起之前将终端重置到安全状态。

终端交互

  • SIGHUP(“hangup”)是在程序运行时关闭 xterm(或以其他方式断开终端连接)时发生的情况。
  • SIGTTINSIGTTOU如果程序在后台运行时尝试读取或写入终端,则暂停程序。为了SIGTTOU发生这种情况,我认为程序需要写入/dev/tty,而不仅仅是默认的标准输出。

CPU异常触发

这意味着您的程序试图做一些错误的事情。

  • SIGILL指非法或未知的处理器指令。例如,如果您尝试直接访问处理器 I/O 端口,则可能会发生这种情况。
  • SIGFPE表示存在硬件数学错误;程序很可能试图除以零。
  • SIGSEGV意味着您的程序试图访问未映射的内存区域。
  • SIGBUS意味着程序以其他方式错误地访问了内存;我不会在此摘要中详细介绍。

流程交互

  • SIGPIPE如果您在管道的读取器关闭其末端后尝试写入管道,则会发生这种情况。看man 7 pipe
  • SIGCHLD当您创建的子进程退出或挂起(通过SIGSTOP或类似方式)时,就会发生这种情况。

对于自我信号很有用

  • SIGABRT通常是由程序调用该abort()函数引起的,默认情况下会导致核心转储。有点像“紧急按钮”。
  • SIGALRM是由alarm()系统调用引起的,这会导致内核SIGALRM在指定的秒数后将 a 传递给程序。参见man 2 alarmman 2 sleep
  • SIGUSR1SIGUSR2按照程序喜欢的方式使用。它们对于进程之间的信号传递很有用。

由管理员发送

这些信号通常是通过命令从命令提示符发送的kill,或者fgbg的情况下通过命令发送SIGCONT

  • SIGKILLSIGSTOP是不可阻挡的信号。第一个总是立即终止进程;第二个暂停该过程。
  • SIGCONT恢复暂停的进程。
  • SIGTERM是 的可捕获版本SIGKILL

答案3

这是对已经给出的其他答案的补充或补充,包括:

  1. 杀戮信号列表[重复]_
  2. 是什么原因导致发送各种信号?

有关大多数信号的更详细解释,请参阅维基百科:https://en.wikipedia.org/wiki/Signal_(IPC)

最常见的信号之一是SIGINT(或只是)程序中断信号,在进程运行时INTCtrl+发送。C

来自维基百科文章多于:

SIGINT

“信号中断”
SIGINT当用户希望中断进程时, 该信号由进程的控制终端发送到进程。这通常是通过按Ctrl+启动的,但在某些系统上,可以使用C“删除”字符或键。 [12]"break"

如何手动向任何正在运行的进程发送任何信号

是什么导致各种信号被发送到[到正在运行的进程]?

除了导致发送信号的其他程序或击键之外,你做!

运行kill -lkill --list列出可以发送到正在运行的进程的所有信号

示例运行和输出:

$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX    

因此,例如,要发送“警报”信号(如SIGALRMALRM或信号号14),您可以执行以下任一操作:

kill -SIGALRM <pid>
kill -ALRM <pid>
kill -14 <pid>

kill将警报信号发送到 pid 的示例命令123456

kill -SIGALRM 123456
kill -ALRM 123456
kill -14 123456

阅读此内容man kill(已添加重点):

描述

默认信号 killTERM。使用-l-L列出可用信号。特别有用的信号包括HUPINTKILLSTOPCONT0备用信号可以通过三种方式指定:-9-SIGKILL-KILL 负PID值可用于选择整个过程组;请参阅ps命令输出中的 PGID 列。 PID-1是特殊的;它表示除kill进程本身和init之外的所有进程。

查找任何感兴趣的进程 ID (pid),运行这个:

ps aux | grep "some program name string or regular expression to search for"

查找输出行最左侧的信号编号。左起第二列是 PID(进程 ID)号。

如何捕获程序中的任何信号

1. 在 Bash 中

“陷阱”,或者捕捉自定义信号并对其采取行动巴什程序你可以执行以下操作(这会捕获SIGALRM信号):

trap <any_comand_to_run_when_signal_is_received> SIGALRM

这是我在自定义 bash 程序中用来捕获Ctrl+ C“中断”(SIGINT、、INT或信号号)信号的常见陷阱:2

# Trap the Ctrl + C SIGINT signal from this point onward in the bash program so
# that whenever the user presses Ctrl + C, this program prints `Ctrl + C` and
# then exits with exit code 2 (change that to any exit code you'd like to
# return when Ctrl + C is pressed!).
trap 'printf "%s\n" " Ctrl + C"; exit 2' SIGINT

看:服务器故障:Bash 循环 - 当我在命令中按 Control-C 时如何停止循环?

2.在C和C++中

要在 Linux 上捕获 C 或 C++ 中的任何给定信号并对其进行操作,您可以使用sigaction()(最好) 或signal()(不太好,但是 C 标准的一部分)。请参阅我对此的全面回答,以及详细的使用示例:Stack Overflow:sigaction 和 signal 有什么区别?

在 bash 中发送(通过kill)和捕获(通过)信号的示例trap

在这些程序中搜索trap命令(接收信号并对其进行操作)和kill命令(向进程发送信号):

  1. 看这个bash蜈蚣游戏:
    1. 问Ubuntu:命令行贪吃蛇游戏?
    2. 在我的eRCAGuy_hello_world回购协议在这里:蜈蚣游戏.sh

相关内容