APUE笔记:Signals(十)
本文记录《UNIX环境高级编程》第3版 第10章 Signals 的一些知识点。
信号概念
信号是软件中断。信号提供了一种处理异步事件的方法。
首先,每个信号都有一个名字。这些名字都以3个字符 SIG
开头。
在头文件 <signal.h>
中,信号名都被定义为正整数常量(信号编号)。实际上,实现将各信号定义在另一个头文件中,但是该头文件又包括在
<signal.h> 中。
不存在编号为 0 的信号。
许多情况都能产生信号:
终端生成的信号在用户按下某些终端按键时产生。在终端上按 Delete 键(或者很多系统中的Ctrl+C键)通常产生中断信号(
SIGINT)。这是停止一个已失去控制的程序的方法。硬件异常产生信号:除数为0、无效的内存引用等。这些条件通常由硬件检测到,并通知内核。然后内核为该条件发生时正在运行的进程产生适当的信号。例如,对执行一个无效内存引用的进程产生
SIGSEGV信号。进程调用
kill函数可将任意信号发送给另一个进程或进程组。自然,对此有所限制:我们必须是我们要向其发送信号的进程的所有者,或者我们必须是超级用户。用户可用
kill命令将信号发送给其他进程。此命令只是kill函数的接口。常用此命令终止一个失控的后台进程。当某个进程需要获知各种事件时,软件条件能够生成信号。这里指的不是硬件产生条件(如除以 0),而是软件条件。例如
SIGURG(当网络连接上有带外数据到达时产生)、SIGPIPE(当进程向没有读取器的管道写入数据时产生)以及SIGALRM(当进程设置的闹钟到期时产生)。
在某个信号出现时,可以告诉内核按下列3种方式之一进行处理,称之为信号的处理或与信号相关的动作。
(1)忽略此信号。大多数信号都可使用这种方式进行处理,但有两种信号却决不能被忽略。它们是
SIGKILL和SIGSTOP。这两种信号不能被忽略的原因是:它们向内核和超级用户提供了使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号(如非法内存引用或除以0),则进程的运行行为是未定义的。(2)捕捉信号。为了做到这一点,要通知内核在某种信号发生时,调用一个用户函数。在用户函数中,可执行用户希望对这种事件进行的处理。注意,不能捕捉
SIGKILL和SIGSTOP信号。(3)执行系统默认动作。
在下列条件下不产生core文件:(a)进程是设置用户ID的,而且当前用户并非程序文件的所有者;(b)进程是设置组ID的,而且当前用户并非该程序文件的组所有者;(c)用户没有写当前工作目录的权限;(d)文件已存在,而且用户对该文件没有写权限;(e)文件太大(RLIMIT_CORE
限制)。
Type man 7 signal see more related to signals in
Linux.
函数signal
UNIX系统信号机制最简单的接口是signal函数。
1 |
|
signal 函数由ISO C定义。因为ISO
C不涉及多进程、进程组以及终端I/O等,所以它对信号的定义非常含糊,以致于对UNIX系统而言几乎毫无用处。
因为signal的语义与实现有关,所以最好使用 sigaction
函数代替signal函数。
signo 参数是信号名。func 的值是常量
SIG_IGN、常量 SIG_DFL
或当接到此信号后要调用的函数的地址。如果指定
SIG_IGN,则向内核表示忽略此信号(记住有两个信号
SIGKILL 和 SIGSTOP 不能忽略)。如果指定
SIG_DFL,
则表示接到此信号后的动作是系统默认动作。当指定函数地址时,则在信号发生时,调用该函数,这种处理为捕捉该信号,称此函数为信号处理程序或信号捕捉函数。
signal 函数原型说明此函数要求两个参数,返回一个函数指针,而该指针所指向的函数无返回值(void)。第一个参数 signo 是一个整型数,第二个参数是函数指针,它所指向的函数需要一个整型参数,无返回值。signal 的返回值是一个函数地址,该函数有一个整型参数(即最后的(int))。
使用下面的typedef,则可使其简单一些。
typedef void Sigfunc(int);
然后,可将signal函数原型写成:
Sigfunc *signal(int, Sigfunc *);
中断的系统调用
早期UNIX系统的一个特性是:如果进程在执行一个低速系统调用而阻塞期间捕捉到一个信号,则该系统调用就被中断不再继续执行。该系统调用返回出错,其errno
设置为
EINTR。这是基于这样一种假设进行的:既然发生了一个信号,且进程捕获到了该信号,那么很有可能发生了某些事情,这些事情应该会唤醒被阻塞的系统调用。
为了支持这种特性,将系统调用分成两类:低速系统调用和其他系统调用。低速系统调用是可能会使进程永远阻塞的一类系统调用,包括:
如果某些文件类型(管道、终端设备和网络设备)中没有数据,读取操作可能会永远阻塞调用方;
如果这些相同的文件类型无法立即接受数据,写入操作可能会永远阻塞调用者;
打开某些文件类型时会阻塞调用方,直到满足某些条件(例如,打开终端设备时会等待,直到连接的调制解调器接听电话)
pause函数(根据定义,它会使调用进程进入睡眠状态,直到捕获到信号为止)和wait函数;某些
ioctl操作;某些进程间通信函数。
这些慢速系统调用的一个显著例外是任何与磁盘输入/输出相关的操作。尽管对磁盘文件的读取或写入可能会暂时阻塞调用者(当磁盘驱动程序将请求排队,然后执行该请求时),但除非发生硬件错误,否则输入/输出操作总会迅速返回并解除对调用者的阻塞。
例如,中断的系统调用所处理的一种情况是,当一个进程开始从终端设备读取数据,而终端前的用户长时间离开终端时。在这个例子中,该进程可能会被阻塞数小时甚至数天,并且除非系统关闭,否则会一直保持这种状态。
POSIX.1 要求只有中断信号的 SA_RESTART
标志有效时,实现才重启动系统调用。sigaction
函数使用这个标志允许应用程序请求重启动被中断的系统调用。
可重入函数
可重入函数是指在多线程或多任务环境中安全调用的函数。这意味着如果一个函数在执行过程中被中断(例如,由操作系统调度器切换到另一个线程或任务),并且在中断后再次被调用,那么该函数的执行状态不会受到影响,能够正确地返回结果。具体来说,可重入函数具有以下几个特征:
无状态性:可重入函数不依赖于全局或静态变量,或者如果使用它们,则在函数内部对它们的访问是安全的。例如,函数不应修改任何共享数据或状态,除非使用适当的同步机制(如锁)。
局部数据:可重入函数应使用局部变量,这样每个调用都有自己的变量副本,互不干扰。
无副作用:可重入函数在执行时不应产生影响外部状态的副作用,例如不应修改全局变量、文件等。
可并发执行:可重入函数可以被多个线程或任务并发调用,而不会导致数据竞争或不一致的状态。
可靠信号术语和语义
首先,当造成信号的事件发生时,为进程生成一个信号(或向进程发送一个信号)。事件可以是硬件异常(如除以 0)、软件条件(如alarm 定时器过期)、终端产生的信号或调用kill 函数。当一个信号产生时,内核通常在进程表中以某种形式设置一个标志。
我们说,当为某个信号执行相应操作时,该信号就被传递到了一个进程。在信号产生到其被传递的这段时间里,这个信号被称为处于未决状态(pending)。
进程可以选择阻止信号的传递。如果为某个进程生成了一个被阻塞的信号,并且该信号的处理动作是默认动作或捕获该信号,那么该信号会一直处于待处理状态,直到进程要么(a)解除对该信号的阻塞,要么(b)将处理动作改为忽略该信号。系统会在信号被递送(而非生成)时决定如何处理被阻塞的信号。这使得进程可以在信号被递送前更改对该信号的处理动作。进程可以调用
sigpending 函数来确定哪些信号处于被阻塞且未决的状态。
如果一个被阻塞的信号在进程解除对该信号的阻塞之前被多次生成,会发生什么情况?POSIX.1允许系统要么只递送一次该信号,要么递送多次。如果系统多次递送该信号,我们就说这些信号被排队了。然而,大多数UNIX系统不会对信号进行排队,除非它们支持POSIX.1的实时扩展。相反,UNIX内核只会递送一次该信号。
如果多个信号准备好要传递给一个进程,会发生什么情况?POSIX.1
没有规定这些信号传递给进程的顺序。不过,POSIX.1
的基本原理确实建议,与进程当前状态相关的信号应在其他信号之前传递(SIGSEGV
就是这样一种信号)。
每个进程都有一个信号掩码,它定义了当前被阻止传递到该进程的一组信号。我们可以将这个掩码视为每个可能的信号都有一个对应的位。如果某个给定信号的位是开启的,那么该信号当前就处于被阻塞状态。进程可以通过调用
sigprocmask 来检查和更改其当前的信号掩码。
信号编号可能会超过一个整型所包含的二进制位数,因此 POSIX.1
定义了一个新数据类型
sigset_t,它可以容纳一个信号集。例如,信号掩码就存储在这些信号集之一中。
函数kill和raise
kill 函数将信号发送给进程或进程组。raise
函数则允许进程向自身发送信号。
1 |
|
调用 raise(signo); 等价于调用
kill(getpid(), signo);
kill 的 pid 参数有以下4种不同的情况。
pid > 0 将该信号发送给进程ID为pid的进程。
pid == 0
该信号会发送给所有满足以下条件的进程:其进程组ID与发送者的进程组ID相同,且发送者有权限向其发送信号。请注意,“所有进程”这一术语不包括一组由实现定义的系统进程。对于大多数UNIX系统而言,这组系统进程包括内核进程和init进程(进程ID为1)。
pid < 0
该信号会发送给所有进程组ID等于pid绝对值且发送者有权向其发送信号的进程。同样,所有进程的集合不包括某些系统进程,如前所述。
pid == −1
该信号会发送到系统上所有发送者有权限向其发送信号的进程。和之前一样,这组进程不包括某些系统进程。
如果被发送的信号是
SIGCONT,则进程可将它发送给属于同一会话的任一其他进程。
如果对 kill
的调用导致为调用进程生成信号,且该信号未被阻塞,那么在kill返回之前,要么signo信号,要么其他一些未决且未被阻塞的信号会被传递给该进程。
函数alarm和pause
使用 alarm
函数可以设置一个定时器(闹钟时间),在将来的某个时刻该定时器会超时。当定时器超时时,产生
SIGALRM
信号。如果忽略或不捕捉此信号,则其默认动作是终止调用该
alarm 函数的进程。
1 |
|
参数 seconds 的值是产生信号 SIGALRM
需要经过的时钟秒数。当这一时刻到达时,信号由内核产生,不过,由于处理器调度延迟,在进程获得控制权来处理信号之前,可能还会有额外的时间流逝。
每个进程中只有一个这样的闹钟。如果在调用 alarm
时,该进程先前注册的闹钟尚未过期,那么该闹钟剩余的秒数将作为此函数的返回值。而先前注册的闹钟会被新值取代。
虽然 SIGALRM
的默认动作是终止进程,但是大多数使用闹钟的进程捕捉此信号。如果此时进程要终止,则在终止之前它可以执行所需的清理操作。如果我们想捕捉
SIGALRM 信号,则必须在调用 alarm
之前安装该信号的处理程序。
pause 函数使调用进程挂起直至捕捉到一个信号。
1 |
|
只有执行了一个信号处理程序并从其返回时,pause才返回。在这种情况下,pause返回−1,
errno设置为 EINTR。
信号集
我们需要一种数据类型来表示多个信号——即信号集(signal
set)。我们会将这种数据类型与 sigprocmask
等函数配合使用,以告知内核不允许该集合中的任何信号发生。POSIX.1定义了
sigset_t
数据类型来包含一个信号集,并定义了以下五个函数来操作信号集。
1 |
|
函数sigprocmask
进程的信号掩码是当前被阻止递送到该进程的一组信号。进程可以通过调用以下函数来检查其信号掩码、更改其信号掩码,或者在一个步骤中执行这两种操作。
1 |
|
首先,若 oset 是非空指针,那么进程的当前信号掩码通过
oset 返回。
其次,若 set 是一个非空指针,则参数 how
指示如何修改当前信号屏蔽字。下表说明了 how
可选的值。SIG_BLOCK 是或操作,而 SIG_SETMASK
则是赋值操作。注意,不能阻塞 SIGKILL 和
SIGSTOP 信号。
| how | Description |
|---|---|
| SIG_BLOCK | The new signal mask for the process is the union of
its current signal mask and the signal set pointed to by
set. That is, set contains the additional
signals that we want to block. |
| SIG_UNBLOCK | The new signal mask for the process is the
intersection of its current signal mask and the
complement of the signal set pointed to by
set. That is, set contains the signals that we
want to unblock. |
| SIG_SETMASK | The new signal mask for the process is replaced by
the value of the signal set pointed to by set. |
如果 set
是个空指针,则不改变该进程的信号掩码,how
的值也无意义。
在调用 sigprocmask
后如果有任何未决的、不再阻塞的信号,则在 sigprocmask
返回前,至少将其中之一递送给该进程。
调用 sigprocmask
之后,如果存在任何未阻塞且处于挂起状态的信号,那么在sigprocmask
返回之前,这些信号中至少有一个会被传递给该进程。
sigprocmask
是仅为单线程进程定义的。处理多线程进程中信号的屏蔽使用另一个函数。
函数sigpending
sigpending
函数返回对调用进程而言被阻塞无法传递且当前处于挂起状态的信号集。该信号集通过
set 参数返回。
1 |
|
函数sigaction
sigaction函数的功能是检查或修改(或检查并修改)与指定信号相关联的处理动作。此函数取代了UNIX早期版本使用
signal 函数。在本节末尾用 sigaction 函数实现了
signal。
1 |
|
其中,参数 signo 是要检测或修改其具体动作的信号编号。若
act 指针非空,则要修改其动作。如果 oact
指针非空,则系统经由 oact
指针返回该信号的上一个动作。此函数使用下列结构:
1 | struct sigaction { |
当更改信号动作时,如果 sa_handler
字段包含一个信号捕捉函数的地址(不是常量 SIG_IGN 或
SIG_DFL),则 sa_mask
字段说明了一个信号集,在调用该信号捕捉函数之前,这一信号集要加到进程的信号掩码中。仅当从信号捕捉函数返回时再将进程的信号掩码恢复为原先值。这样,在调用信号处理程序时就能阻塞某些信号。操作系统在调用处理程序时,会将正在传递的信号包含在信号掩码中。因此,我们可以确保,每当我们处理某个特定信号时,该信号的另一次出现会被阻塞,直到我们处理完第一次出现的信号为止。同一信号的额外出现通常不会被排队。如果该信号在被阻塞期间出现了五次,那么当我们解除对该信号的阻塞时,该信号的信号处理函数通常只会被调用一次。
一旦为某个特定信号安装了一个动作,该动作会一直保持安装状态,直到我们通过调用
sigaction
来明确更改它。与早期系统中那些不可靠的信号不同,POSIX.1要求信号处理程序在被明确更改前一直保持安装状态。
act 结构体的 sa_flags
字段指定了处理该信号的各种选项。下图详细说明了这些选项被设置时的含义。

sa_sigaction字段是一个替代的信号处理程序,在
sigaction 结构中使用了 SA_SIGINFO
标志时,使用该信号处理程序。对于 sa_sigaction
字段和sa_handler
字段两者,实现可能使用同一存储区,所以应用只能一次使用这两个字段中的一个。
sa_sigaction 字段是一种替代信号处理程序,当与
sigaction 一起使用SA_SIGINFO
标志时会用到它。实现可能会为 sa_sigaction 字段和
sa_handler
字段使用相同的存储空间,因此应用程序一次只能使用这两个字段中的一个。
通常,按下列方式调用信号处理程序:
void handler(int signo);
但是,如果设置了 SA_SIGINFO
标志,那么按下列方式调用信号处理程序:
void handler(int signo, siginfo_t *info, void *context);
siginfo
结构包含了信号产生原因的有关信息。该结构的大致样式如下所示。符合POSIX.1的所有实现必须至少包括
si_signo 和 si_code
成员。另外,符合XSI的实现至少应包含下列字段:
1 | struct siginfo { |
函数sigsetjmp和siglongjmp
调用 longjmp
有一个问题。当捕捉到一个信号时,进入信号捕捉函数,此时当前信号被自动地加到进程的信号屏蔽字中。这阻止了后来产生的这种信号中断该信号处理程序。如果用
longjmp
跳出信号处理程序,那么,对此进程的信号屏蔽字会发生什么呢?
在FreeBSD 8.0和Mac OS X
10.6.8中,setjmp和longjmp保存和恢复信号屏蔽字。但是, Linux
3.2.0和Solaris
10并不执行这种操作,虽然Linux支持提供BSD行为的选项。FreeBSD 8.0和Mac OS
X
10.6.8提供函数_setjmp和_longjmp,它们也不保存和恢复信号屏蔽字。
为了允许两种形式并存,POSIX.1并没有指定 setjmp 和
longjmp 对信号屏蔽字的作用,而是定义了两个新函数
sigsetjmp 和
siglongjmp。在信号处理程序中进行非局部转移时应当使用这两个函数。
1 |
|
这两个函数和 setjmp、longjmp
之间的唯一区别是 sigsetjmp 增加了一个参数。如果
savemask 非0,则 sigsetjmp 在 env
中保存进程的当前信号屏蔽字。调用 siglongjmp 时,如果带非0
savemask 的 sigsetjmp 调用已经保存了
env,则 siglongjmp
从其中恢复保存的信号屏蔽字。
函数sigsuspend
需要在一个原子操作中先恢复信号屏蔽字,然后使进程休眠。这种功能是由
sigsuspend 函数所提供的。
1 |
|
进程的信号屏蔽字设置为由 sigmask
指向的值。在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则
sigsuspend 返回,并且该进程的信号屏蔽字设置为调用
sigsuspend 之前的值。
注意,此函数没有成功返回值。如果它返回到调用者,则总是返回−1,并将
errno 设置为
EINTR(表示一个被中断的系统调用)。
函数abort
abort 函数的功能是使程序异常终止。
1 |
|
此函数将 SIGABRT
信号发送给调用进程(进程不应忽略此信号)。ISO C规定,调用
abort
将向主机环境递送一个未成功终止的通知,其方法是调用raise(SIGABRT)
函数。
ISO C要求若捕捉到此信号而且相应信号处理程序返回, abort
仍不会返回到其调用者。如果捕捉到此信号,则信号处理程序不能返回的唯一方法是它调用exit、_exit、_Exit、longjmp
或 siglongjmp。POSIX.1也说明 abort
并不理会进程对此信号的阻塞和忽略。
函数sleep、nanosleep和clock_nanosleep
1 |
|
此函数使调用进程被挂起直到满足下面两个条件之一。
(1)已经过了 seconds 所指定的墙上时钟时间。
(2)调用进程捕捉到一个信号并从信号处理程序返回。
如同 alarm
信号一样,由于其他系统活动,实际返回时间比所要求的会迟一些。
在第1种情形,返回值是0。当由于捕捉到某个信号sleep提早返回时(第2种情形),返回值是未休眠完的秒数(所要求的时间减去实际休眠时间)。
FreeBSD 8.0、Linux 3.2.0、Mac OS X 10.6.8和Solaris 10用
nanosleep
函数实现sleep,使sleep具体实现与信号和闹钟定时器相互独立。
nanosleep
函数与sleep函数类似,但提供了纳秒级的精度。
1 |
|
这个函数挂起调用进程,直到要求的时间已经超时或者某个信号中断了该函数。
reqtp
参数用秒和纳秒指定了需要休眠的时间长度。如果某个信号中断了休眠间隔,进程并没有终止,remtp
参数指向的 timespec
结构就会被设置为未休眠完的时间长度。如果对未休眠完的时间并不感兴趣,可以把该参数置为NULL。
如果系统并不支持纳秒这一精度,要求的时间就会取整。因为
nanosleep
函数并不涉及产生任何信号,所以不需要担心与其他函数的交互。
随着多个系统时钟的引入,需要使用相对于特定时钟的延迟时间来挂起调用线程。clock_nanosleep
函数提供了这种功能。
1 |
|
clock_id
参数指定了计算延迟时间基于的时钟。flags
参数用于控制延迟是相对的还是绝对的。flags
为0时表示休眠时间是相对的(例如,希望休眠的时间长度),如果flags值设置为
TIMER_ABSTIME,表示休眠时间是绝对的(例如,希望休眠到时钟到达某个特定的时间)。
注意,除了出错返回,调用
clock_nanosleep(CLOCK_REALTIME, 0, reqtp, remtp);和调用
nanosleep(reqtp, remtp);的效果是相同的。使用相对休眠的问题是有些应用对休眠长度有精度要求,相对休眠时间会导致实际休眠时间比要求的长。例如,某个应用程序希望按固定的时间间隔执行任务,就必须获取当前时间,计算下次执行任务的时间,然后调用nanosleep。在获取当前时间和调用nanosleep之间,处理器调度和抢占可能会导致相对休眠时间超过实际需要的时间间隔。即便分时进程调度程序对休眠时间结束后是否会马上执行用户任务并没有给出保证,使用绝对时间还是改善了精度。
函数sigqueue
通常一个信号带有一个位信息:信号本身。除了对信号排队以外,这些扩展允许应用程序在递交信号时传递更多的信息。这些信息嵌入在
siginfo
结构中。除了系统提供的信息,应用程序还可以向信号处理程序传递整数或者指向包含更多信息的缓冲区指针。
使用排队信号必须做以下几个操作。
(1)使用 sigaction函数安装信号处理程序时指定SA_SIGINFO标志。如果没有给出这个标志,信号会延迟,但信号是否进入队列要取决于具体实现。
(2)在
sigaction结构的sa_sigaction成员中(而不是通常的sa_handler字段)提供信号处理程序。实现可能允许用户使用sa_handler字段,但不能获取sigqueue函数发送出来的额外信息。(3)使用
sigqueue函数发送信号。
1 |
|
sigqueue 函数只能把信号发送给单个进程,可以使用
value
参数向信号处理程序传递整数和指针值,除此之外,sigqueue
函数与 kill 函数类似。
信号不能被无限排队。到达相应的 SIGQUEUE_MAX
限制以后,sigqueue 就会失败,将 errno 设为
EAGAIN。
下图总结了排队信号在不同的实现中的行为上的差异。

作业控制信号
POSIX.1认为有以下6个信号与作业控制有关。
SIGCHLD 子进程已停止或终止。
SIGCONT 如果进程已停止,则使其继续运行。
SIGSTOP 停止信号(不能被捕捉或忽略)。
SIGTSTP 交互式停止信号。
SIGTTIN 后台进程组成员读控制终端。
SIGTTOU 后台进程组成员写控制终端。
除 SIGCHLD
以外,大多数应用程序并不处理这些信号,交互式shell则通常会处理这些信号的所有工作。当键入挂起字符(通常是Ctrl+Z)时,SIGTSTP被送至前台进程组的所有进程。当我们通知shell在前台或后台恢复运行一个作业时,shell向该作业中的所有进程发送SIGCONT信号。与此类似,如果向一个进程递送了SIGTTIN或SIGTTOU信号,则根据系统默认的方式,停止此进程,作业控制shell了解到这一点后就通知我们。
一个例外是管理终端的进程,例如,vi(1)编辑器。当用户要挂起它时,它需要能了解到这一点,这样就能将终端状态恢复到 vi 启动时的情况。另外,当在前台恢复它时,它需要将终端状态设置回它所希望的状态,并需要重新绘制终端屏幕。
在作业控制信号间有某些交互。当对一个进程产生 4
种停止信号(SIGTSTP、SIGSTOP、SIGTTIN或SIGTTOU)中的任意一种时,对该进程的任一未决SIGCONT
信号就被丢弃。与此类似,当对一个进程产生 SIGCONT
信号时,对同一进程的任一未决停止信号被丢弃。
注意,如果进程是停止的,则 SIGCONT
的默认动作是继续该进程;否则忽略此信号。通常,对该信号无需做任何事情。当对一个停止的进程产生一个
SIGCONT
信号时,该进程就继续,即使该信号是被阻塞或忽略的也是如此。
信号名和编号
本节介绍如何在信号编号和信号名之间进行映射。某些系统提供数组
extern char *sys_siglist[];
数组下标是信号编号,数组中的元素是指向信号名符串的指针。
FreeBSD 8.0、Linux 3.2.0和Mac OS X
10.6.8都提供这种信号名数组。Solaris
10也提供信号名数组,但该数组名是_sys_siglist。
可以使用 psignal
函数可移植地打印与信号编号对应的字符串。
1 |
|
字符串
msg(通常是程序名)输出到标准错误文件,后面跟随一个冒号和一个空格,再后面对该信号的说明,最后是一个换行符。如果msg为
NULL,只有信号说明部分输出到标准错误文件,该函数类似于
perror。
如果在 sigaction 信号处理程序中有
siginfo结构,可以使用 psiginfo
函数打印信号信息。
1 |
|
它的工作方式与 psignal
函数类似。虽然这个函数访问除信号编号以外的更多信息,但不同的平台输出的这些额外信息可能有所不同。
如果只需要信号的字符描述部分,也不需要把它写到标准错误文件中(如可以写到日志文件中),可以使用
strsignal 函数,它类似于 strerror。
1 |
|
给出一个信号编号,strsignal
将返回描述该信号的字符串。应用程序可用该字符串打印关于接收到信号的出错消息。