关于标准信号的传送

相反,如果标准信号的多个实例在该信号当前被阻塞的情况下被传送,则仅一个实例被排队。

我认为上面的描述不是那么清楚,对我造成不明确的影响:

如果特定信号没有被阻塞 ,那么同一个信号的多个实例是否会排队呢?

排队的信号在哪里,过程特定的位置还是全球的位置?

如何处理排队的信号,是否有可能同时处理两个信号,或保证信号将被逐一处理?

所以这里其实有三个问题

如果特定信号没有被阻塞,那么同一个信号的多个实例是否会排队呢?

它取决于使用sigaction结构和sigaction()函数是否为信号设置了SA_SIGINFO标志,以及系统是否具有_POSIX_REALTIME_SIGNALS(现代Linux内核)的有效定义。 如果两个实例均为真,那么符合这两个条件的任何到达的信号将排队在每个进程队列中,直到它们被交付或接受达到操作系统针对给定信号的队列中的项目数限制。 在此之后,任何其他到达该信号类型的信号都将被丢弃。

如果其中任何一种情况都不正确,则只处理当前到达的信号,并丢弃当前信号处理器正在运行时到达的相同信号类型的任何其他信号。 此外,如果您阻止信号,并且有两个或更多的信号到达过程并且未被传送,则它们合并成单个信号事件。 但是同样,只有在上述两个条件都不满足的情况下,否则相同类型的多个信号事件排队。

还有一点需要注意……这两个条件是针对POSIX规范的,但即使SA_SIGINFO没有为该信号设置,Linux也会对任何实时信号进行排队。 所以这意味着对应于范围SIGRTMIN和SIGRTMAX的任何信号。

排队的信号在哪里,过程特定的位置还是全球的位置?

它存储在每个进程队列中。

如何处理排队的信号,是否有可能同时处理两个信号,或保证信号将被逐一处理?

这取决于如何使用sigaction struture和sigaction()函数设置信号处理程序。 当信号处理程序运行时,不能保证其他信号会被阻塞。 信号掩码可以在sigaction结构中设置,以确定在信号处理程序运行时哪些信号被阻塞。 信号本身被阻塞,直到信号处理程序完成,但如果信号处理程序没有被设置在您的信号处理程序中的信号处理程序的信号掩码阻塞,那么其他信号可能会中断当前的信号处理程序。 因此,在信号处理程序中所做的任何操作都应该是异步安全的,并且不应该在fprintf()等信号处理程序中调用任何非异步安全函数。因此,可以保证信号本身在FIFO中处理(即一个信号不会自行中断),但是如果你没有故意阻塞它,其他信号可能会中断你当前的信号处理程序。 请记住,在信号处理程序中设置一个信号掩码,试图阻止其他信号中断你的处理程序是一个非常糟糕的主意,而不是一个原子操作,所以不要这样做。 如果您希望在信号处理程序运行时阻塞其他信号,请在传递给sigaction()sigaction结构中提供一个信号掩码。

这是一个掩码 – 注意到标准信号的值都低于32

编辑0:

标准信号的“队列”仅仅是每个线程的一个位掩码,所以一旦信号被发送并且还没有被传送,则给定位被设置,并且发送相同的信号丢失,直到该位被清除,即信号被传送。

编辑1:

我们可以可靠地获取子进程,因为该机制不仅仅依赖于信号。 内核保存有关进程血统的详细信息,并且子进程一旦退出就不会消失,而是留在进程表中供父进程获取(这就是我们如何培育僵尸,正确:)。 等待SIGCHLD意味着“至少有一个孩子改变了状态,进入内核收集尸体”。 这里的竞争并不在信号“队列”上,而是在进程表/树/任何内容上,这是内核保护它的工作。

如果在处理相同的信号的同时传递信号,处理器将在从当前调用返回之后再次被调用,所以将会有多个信号传送。

当然,如果在处理第一个信号时多次发送信号,则只有一个信号将被排队,并且只有一个重复的处理程序调用将会发生。

信号在内核的proc结构中被标记为“未决”,所以每个进程都有独立的信号位掩码,每种信号只有一个(SIGBUS,SIGINT,SIGUSR1等)可以挂起,但是几个不同的信号可能同时挂起。

一个信号在每个线程中一次处理。 信号处理程序运行时,所有其他信号都会自动阻止。

所以不可能将多个相同的信号排队到单个线程。 然而,许多不同的信号可以出现在队列中。

我认为信号处理程序可能会在信号退出之前解除某些信号,在这种情况下,如果信号的生成速度快于信号堆栈的速度,则会导致信号堆栈(用于信号处理程序的调用堆栈,而不是信号队列)溢出的风险可以被处理。