Answers:
除了“信号过多”问题外,还可以显式忽略信号。来自man 2 signal
:
If the signal signum is delivered to the process, then one of the
following happens:
* If the disposition is set to SIG_IGN, then the signal is ignored.
信号也可以被阻塞。来自man 7 signal
;
A signal may be blocked, which means that it will not be delivered
until it is later unblocked. Between the time when it is generated
and when it is delivered a signal is said to be pending.
子进程会继承被阻塞和被忽略的信号集,因此您的应用程序的父进程可能会忽略或阻塞这些信号之一。
在过程完成处理之前的信号之前传递多个信号会发生什么?这取决于操作系统。signal(2)
上面链接的联机帮助页对此进行了讨论:
libc
,但是我希望BSD的行为。您不能相信发送的每个信号都会被传递。例如,如果某个进程在处理已存在的子进程中的SIGCHLD上花费很长时间,则linux内核会“凝聚” SIGCHLD。
为了回答您的问题的另一部分,如果许多不同的信号以太短的间隔到达,则信号在内核内部“排队”。
您应该使用sigaction()
的sa_sigaction
成员来设置信号处理程序,仔细siginfo_t
设置参数的sa_mask
成员siginfo_t
。我认为这意味着至少要掩盖所有“异步”信号。根据Linux的手册页sigaction()
,您还将屏蔽正在处理的信号。我认为您应该将sa_flags
成员设置为SA_SIGINFO,但是我不记得为什么会有这种迷信。我相信这将为您的进程提供一个信号处理程序,该信号处理程序在没有竞争条件的情况下保持不变,并且不会被大多数其他信号打断。
非常非常小心地编写信号处理程序函数。基本上只是设置一个全局变量以指示信号被捕获,然后让其余过程处理该信号的所需动作。这样,信号将被屏蔽最少的时间。
另外,您将要非常彻底地测试信号处理代码。将其放在一个小的测试过程中,并发送尽可能多的SIGUSR1和SIGUSR2信号,可能是从2个或3个特殊目的的信号发送程序发出的。在确信自己的代码可以快速正确地处理SIGUSR1和SIGUSR2之后,还请混入其他一些信号。准备好进行困难的调试。
如果仅使用linux,则可能会考虑使用signalfd()
创建文件描述符,您可以对其进行select()
轮询或轮询以接收这些信号。使用signalfd()
可能会使调试更容易。
从某种意义上说,如果过程成功调用,则可以保证传递信号 kill
,则目标将接收信号。这是异步的:发送者无法知道何时接收或处理信号。但是,这不能保证会传送信号。目标可能在处理信号之前死亡。如果目标在传递信号时忽略了该信号,则该信号将无效。如果目标在处理信号之前接收到多个具有相同信号编号的实例,则这些信号可能会(通常是合并):如果您向一个进程发送两次相同的信号,您将无法知道该进程是否会接收到该信号一两次。信号主要是为了杀死进程而设计的,或者是使进程引起注意的一种方式,它们并不是为了进行通信而设计的。
如果您需要可靠的交付,则需要不同的通信机制。进程之间有两种主要的通信机制:管道允许单向通信;一个套接字允许双向通信和到同一服务器的多个连接。如果您需要目标处理与发送时一样多的通知,请通过管道发送字节。
如果在阻塞时传送了多个信号,则内核可以自由合并标准信号。另一方面,实时信号也没有类似的障碍。
实时信号的特征如下:
- 实时信号的多个实例可以排队。相比之下,如果在当前阻塞标准信号的情况下传递了该信号的多个实例,则仅将一个实例排队。
尝试使用数字范围为SIGRTMIN至SIGRTMAX的信号。
ulimit -i
在Ubuntu 18.04上显示为63432。
signal(2)
着重建议您通过使用sigaction(2)
来避免这种混乱。