信号可以忽略(丢失)吗?


9

我有一个通过信号(特殊SIGUSR1 / SIGUSR2 / SIGSTOP)与工作人员通信的应用程序。

我可以相信,无论发生什么情况,处理程序都会传递和处理每个信号?

如果发送信号的速度比应用程序无法处理的速度更快(例如,由于当前主机负载过大),会发生什么?

Answers:


8

除了“信号过多”问题外,还可以显式忽略信号。来自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)上面链接的联机帮助页对此进行了讨论:

  • 系统V会将信号处理重置为默认设置。更糟糕的是,多个信号的快速传递将导致递归(?)调用。
  • BSD将自动阻止信号,直到处理程序完成为止。
  • 在Linux上,这取决于为GNU设置的编译标志libc,但是我希望BSD的行为。

4
Linux的手册页signal(2)着重建议您通过使用sigaction(2)来避免这种混乱。
Nate Eldredge

7

您不能相信发送的每个信号都会被传递。例如,如果某个进程在处理已存在的子进程中的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()可能会使调试更容易。


2
合并的不仅是SIGCLD:如果在处理信号之前已将所有信号传递出去,则可能会合并所有信号。
吉尔(Gilles)'所以

是否有度量SIGCHLD信号的“太长”时间?我现在在程序中遇到这种行为,我的信号处理程序花费的时间也不会超过100ms。
xrisk

@Rishav-据我所知,没有办法找出“太长”的含义。我希望整体系统负载很重要。也就是说,其他进程和内核正在执行的操作将影响信号之间的“持续时间”,以使它们合并。我认为这不是一个有用的答案。
Bruce Ediger

6

从某种意义上说,如果过程成功调用,则可以保证传递信号 kill,则目标将接收信号。这是异步的:发送者无法知道何时接收或处理信号。但是,这不能保证会传送信号。目标可能在处理信号之前死亡。如果目标在传递信号时忽略了该信号,则该信号将无效。如果目标在处理信号之前接收到多个具有相同信号编号的实例,则这些信号可能会(通常是合并):如果您向一个进程发送两次相同的信号,您将无法知道该进程是否会接收到该信号一两次。信号主要是为了杀死进程而设计的,或者是使进程引起注意的一种方式,它们并不是为了进行通信而设计的。

如果您需要可靠的交付,则需要不同的通信机制。进程之间有两种主要的通信机制:管道允许单向通信;一个套接字允许双向通信和到同一服务器的多个连接。如果您需要目标处理与发送时一样多的通知,请通过管道发送字节。


4
您是不是要写“保证信号已被传送”,因为您继续描述了信号不被传送的一些方式(即,在接收到信号之前进程已死,或者信号已合并)?
约翰尼

2

如果在阻塞时传送了多个信号,则内核可以自由合并标准信号。另一方面,实时信号也没有类似的障碍。

signal(7)手册页

实时信号的特征如下:

  1. 实时信号的多个实例可以排队。相比之下,如果在当前阻塞标准信号的情况下传递了该信号的多个实例,则仅将一个实例排队。

尝试使用数字范围为SIGRTMIN至SIGRTMAX的信号。


实时信号有一定的限制,但是相当高。如果用户发送的未决挂起信号的数量超过RLIMIT_SIGPENDING,则信号将被丢弃。ulimit -i在Ubuntu 18.04上显示为63432。
贝恩
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.