我对在编程中使用信号并不陌生。我主要使用 C/C++ 和 Python 工作。 但我有兴趣了解信号在 Linux(或 Windows)中实际是如何实现的。
操作系统是否在信号描述符表中的每个 CPU 指令之后检查是否还有任何已注册的信号需要处理?或者流程管理器/调度器对此负责?
由于信号是异步的,CPU指令在完成之前是否会中断?
操作系统绝对不会处理每条指令。决不。太慢了。
当 CPU 遇到问题(例如除以 0、访问受限资源或没有物理内存备份的内存位置)时,它会生成一种特殊的中断,称为异常(不要与 C++/ Java/等高级语言异常摘要)。
操作系统处理这些异常。如果需要并且可能的话,它可以将异常反映回其起源的进程中。 Windows中所谓的结构化异常处理(SEH)就是这种反射。 C 信号应该使用相同的机制来实现。
在我熟悉的系统上(尽管我不明白为什么在其他地方应该有很大不同),信号传递是在进程从内核返回到用户模式时完成的。
我们先考虑单CPU的情况。信号有以下三种来源:
在所有这些情况下,目标进程不是在用户态运行,而是在内核模式运行。要么通过系统调用,要么通过上下文切换(因为除非我们的目标进程没有运行,否则其他进程无法发送信号),或者通过中断处理程序。因此,信号传递是一个简单的问题,即在从内核模式返回用户态之前检查是否有任何信号要传递。
在多 cpu 情况下,如果目标进程在另一个 cpu 上运行,则只需向其运行的 cpu 发送中断即可。中断只是强制另一个 cpu 进入内核模式并返回,以便可以在返回时完成信号处理。
一个进程可以向另一个进程发送信号。进程可以注册自己的信号处理程序来处理每个信号。 (注意,在Linux上,SIGKILL不能被捕获)。
当进程执行信号处理程序时,它会阻塞同一个信号,也就是说,当信号处理程序正在执行时,如果另一个相同的信号到达,它不会调用信号处理程序[称为阻塞信号],但它会注意到信号已到达[即:待处理信号]。一旦执行了已经运行的信号处理程序,就会处理挂起的信号。如果您不想运行待处理信号,则可以忽略该信号。
上述概念中的问题是:
假设如下: 进程 A 已注册 SIGUSR1 的信号处理程序。
1) process A gets signal SIGUSR1, and executes signalhandler()
2) process A gets SIGUSR1,
3) process A gets SIGUSR1,
4) process A gets SIGUSR1,
当步骤(2)发生时,是否设为“待处理信号”。 IE;它需要被服务。 当步骤(3)发生时,它被忽略,因为只有一位 可用于指示每个可用信号的待处理信号。
为了避免这样的问题,即:如果我们不想丢失信号,那么我们可以使用 实时信号。
信号同步执行,
例如,
1) process is executing in the middle of signal handler for SIGUSR1,
2) Now, it gets another signal SIGUSR2,
3) It stops the SIGUSR1, and continues with SIGUSR2,
and once it is done with SIGUSR2, then it continues with SIGUSR1.
恕我直言,我记得检查是否有任何信号已到达进程的是:
希望这能在一定程度上有所帮助。