我有时会对进程可以接收的所有信号感到困惑。据我了解,一个进程对这些信号中的每一个都有一个默认处理程序(信号处置),但它可以通过调用sigaction().
所以这是我的问题:是什么导致每个信号被发送?我意识到您可以通过-s参数 to手动向正在运行的进程发送信号kill,但是发送这些信号的自然情况是什么?例如,什么时候SIGINT发送?
另外,对可以处理哪些信号有任何限制吗?甚至SIGSEGV可以处理信号并将控制权返回给应用程序吗?
Gil*_*il' 47
除了进程调用之外kill(2),一些信号是由内核(或有时由进程本身)在各种情况下发送的:
SIGALRM通知进程设置的计时器已到期。定时器可以用alarm、setitimer和其他来设置。SIGCHLD 通知进程它的一个子进程已经死亡。SIGPIPE当一个进程在读取端关闭时尝试写入管道时生成(这个想法是,如果您运行foo | bar并bar退出,则会foo被 a 杀死SIGPIPE)。SIGPOLL(也称为SIGIO)通知进程发生了可轮询事件。POSIX 指定通过I_SETSIG ioctl. 许多系统允许通过O_ASYNC fcntl标志设置的任何文件描述符上的可轮询事件。一个相关的信号是SIGURG,它通知设备(通过 注册I_SETSIG ioctl)或套接字上的紧急数据。SIGPWR当UPS发出即将发生电源故障的信号时,它会发送到所有进程。这些列表并不详尽。标准信号在signal.h.
大多数信号可以被应用程序捕获和处理(或忽略)。唯一无法捕获的两个可移植信号是SIGKILL(just die) 和STOP(stop execution)。
SIGSEGV(分段错误) 及其表亲SIGBUS(总线错误) 可以被捕获,但除非您真的知道自己在做什么,否则这是一个坏主意。捕获它们的常见应用是打印堆栈跟踪或其他调试信息。更高级的应用是实现某种进程内内存管理,或者在虚拟机引擎中捕获错误指令。
最后,让我提一下不是信号的东西。当您在从终端读取输入的程序中的一行开头按Ctrl+D时,这会告诉程序已到达输入文件的末尾。这不是信号:它是通过输入/输出 API 传输的。像Ctrl+C和朋友一样,可以用stty.
Jan*_*der 20
首先回答你的第二个问题:SIGSTOP并且SIGKILL不能被应用程序捕获,但其他所有信号都可以,甚至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 (“挂断”)是在程序运行时关闭 xterm(或以其他方式断开终端)时发生的情况。SIGTTINSIGTTOU如果程序在后台运行时尝试读取或写入终端,请暂停您的程序。为了SIGTTOU发生,我认为程序需要写入/dev/tty,而不仅仅是默认的标准输出。这意味着您的程序试图做错事。
SIGILL表示非法或未知的处理器指令。例如,如果您尝试直接访问处理器 I/O 端口,则可能会发生这种情况。SIGFPE表示存在硬件数学错误;很可能该程序试图除以零。SIGSEGV 意味着您的程序试图访问未映射的内存区域。SIGBUS意味着程序以其他方式错误地访问了内存;我不会详细介绍这个总结。SIGPIPE如果您在管道的读取器关闭其末端后尝试写入管道,则会发生这种情况。见man 7 pipe。SIGCHLD当您创建的子进程退出或暂停(由SIGSTOP或类似)时发生。SIGABRT通常是由程序调用abort()函数引起的,默认情况下会导致核心转储。有点像“紧急按钮”。SIGALRM是由alarm()系统调用引起的,这将导致内核SIGALRM在指定的秒数后将 a传递给程序。见man 2 alarm和man 2 sleep。SIGUSR1并且SIGUSR2使用程序喜欢。它们对于进程之间的信令很有用。这些信号通常从命令提示符发送,通过kill命令,fg或bg在SIGCONT.
SIGKILL和SIGSTOP是不可阻塞的信号。第一个总是立即终止进程;第二个暂停进程。SIGCONT 恢复暂停的进程。SIGTERM是一个可捕获的版本SIGKILL。