本文主要是介绍APUE——Chapter 10:信号,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
信号是软件中断。信号提供了一种处理异步事件的方法。
在头文件< signal.h >中,信号名都被定义为正整数常量。 (信号编号)
不存在编号为 0 的信号。
信号处理:
(1)忽略此信号。(有两种信号不能被忽略:SIGKILL、SIGSTOP)。
(2)捕捉信号。(不能捕捉 SIGKILL 和 SIGSTOP 信号)。
(3)执行系统的默认动作。
终止+core。大多数Unix系统调试程序都使用core文件检查进程终止时的状态。
在下列条件下不产生core文件:
(a)进程是设置用户ID的,而且当前用户并非程序文件的所有者。
(b)进程是设置组ID的,而且当前用户并非程序文件的组所有者。
(c)用户没有写当前工作目录的权限。
(d)文件已存在,而且用户对该文件没有写权限。
SIGABRT 调用abort函数时产生此信号。
SIGALRM 当用alarm函数设置的定时器超时时,产生此信号。
SIGCHLD 在一个进程终止或停止时,该信号被送给其父进程。按系统默认,将忽略此信号。
SIGFPE 表示算术运算异常,如除以0、浮点溢出等。
SIGHUP 如果终端接口检测到一个连接断开,则将此信号送给与该终端相关的控制进程(会话首进程)。通常使用此信号通知守护进程再次读取它们的配置文件。选用此信号的理由是:守护进程不会有控制终端,通常决不会接收到这种信号。
SIGILL 表示进程执行一条非法硬件指令。
SIGINT 当用户按下中断键Ctrl+C时,终端驱动程序产生此信号并发送至前台进程组的每一个进程。
SIGIO 指示一个异步I/O事件。
SIGTERM 由kill命令发送的系统默认终止信号。
SIGKILL 不能捕获或忽略。它向管理员提供了一红杀死任一进程的可靠方法。
SIGPIPE 如果在管道的读进程已终止时写管道,则产生此信号。
SIGQUIT 当用户在终端上按下退出键Ctrl+\时,终端驱动程序产生此信号并发送给前台进程组中的所有进程。此信号除了终止前台进程组(和SIGINT一样),同时产生一个core文件。
SIGSEGV 指示进程进行了一次无效的内存引用。
SIGTSTP 交互停止信号。当用户在终端上按下挂起键Ctrl+Z时,终端驱动程序产生此信号,并发送至前台进程组的所有进程。
SIGSTOP 类似于交互停止信号(SIGTSTP),但它不能被捕获或忽略。
SIGCONT 此作业控制信号发送给需要继续运行,但当前处于停止状态的进程。
SIGTTIN 当一个后台进程组进程试图读其控制终端时,终端驱动程序产生此信号。下列情况例外:1. 读进程忽略或阻塞此信号;2. 读进程所属的进程组是孤儿进程组,此时读操作返回出错,errno设置为EIO
SIGTTOU 当一个后台进程组进程试图写其控制终端时,终端驱动程序产生此信号。
SIGURG 通知进程已经发生一个紧急情况。如带外数据到达。
SIGUSR1、SIGUSR2 用户定义的信号,可用于应用程序。
10.1 signal函数
#include <signal.h>void (*signal(int signo, void (*func)(int)))(int);/* 返回值:若成功则返回信号以前的处理配置,若出错则返回SIG_ERR */
最好使用sigaction函数代替signal函数。
signo:信号名。
func:常量SIG_IGN(指向内核表示忽略此信号)、SIG_DFL(表示接到此信号后的动作是系统默认动作)或当接到此信号后要调用的函数的地址。
子进程继承父进程的信号处理方式(信号捕捉函数的地址在子进程中是有意义的)。
没有列入表的大多数函数是不可重入的,原因为:
(a)已知它们使用静态数据结构
(b)它们调用malloc或free
(c)它们是标准I/O函数。
在信号产生(generation)和递送(delivery)之间的时间间隔内,称信号是未决的(pending)。
每个进程都有一个信号屏蔽字(signal mask),它规定了当前要阻塞递送到该进程的信号集。
进程可调用sigprocmask来检测和更改其当前信号屏蔽字。
10.2 kill和raise函数
kill函数将信号发送给进程或进程组。raise函数则允许进程向自身发送信号。
#include <signal.h>int kill(pid_t pid, int signo);int raise(int signo);/* 两个函数返回值:若成功则返回0,若出错则返回-1 */
pid参数:
pid > 0 将该信号发送给进程ID为pid的进程。
pid == 0 将该信号发送给与发送进程属于同一进程组的所有进程。而且发送进程具有向这些进程发送信号的权限。
pid < 0 将该信号发送给其进程ID等于pid的绝对值,而且发送进程具有向这些进程发送信号的权限。
pid == -1 将该信号发送给发送进程有权限向它们发送信号的系统上的所有进程。
发送权限,基本规则是:发送者的实际或有效用户ID必须等于接收者的实际或有效用户ID。
权限测试有一个特例:如果被发送的信号是SIGCONT,则进程可将它发送给属于同一会话的任何其他进程。
编号为0的信号定义为空信号。
如果signo为0,则kill仍执行正常的错误检查,但不发送信号。这常被用来确定一个特定进程是否仍旧存在。如果向一个并不存在的进程发送空信号,则kill返回-1,并将errno设置为ESRCH。
(UNIX系统在经过一段时间后会重新使用进程ID,一个现有的具有所给定进程ID的进程并不一定就是你想要的进程。)
对于进程是否存在这种测试不是原子操作。
10.3 alarm和pause函数
使用alarm函数可以设置一个计时器,在将来某个指定的时间该计时器会超时,则产生SIGALRM信号。默认动作是终止调用该alarm函数的进程。
#include <unistd.h>unsigned int alarm(unsigned int seconds);/* 返回值:0或以前设置的闹钟时间的余留秒数 */
信号由内核产生,由于进程调度的延迟,所以进程得到控制从而能够处理该信号还需一些时间。
每个进程只能有一个闹钟时钟。如果在调用alarm时,以前已为该进程设置过闹钟时钟,而且它还没有超时,则将该闹钟时钟的余留值作为本次alarm函数调用的返回值。以前登记的闹钟时钟则被新值代替。
如果有以前为进程登记的尚未超时的闹钟时钟,而且本次调用的seconds值为0,则取消以前的闹钟时钟,其余留值仍作为alarm函数的返回值。
#include <unistd.h>int pause(void);/* 返回值:-1,并将errno设置为EINTR */
pause函数使调用进程挂起直至捕捉到一个信号。
只有执行了一个信号处理程序并从其返回时,pause才返回。
10.4 信号集
#include <signal.h>int sigemptyset(sigset_t *set);int sigfillset(sigset_t *set);int sigaddset(sigset_t *set, int signo);int sigdelset(sigset_t *set, int signo);/* 四个函数返回值:若成功则返回0,若出错则返回-1 */int sigismember(const sigset_t *set, int signo);/* 返回值:若真则返回1,若假则返回0,若出错则返回-1 */
10.5 sigpromask函数
调用sigpromask可以检测或更改其信号屏蔽字,或者一个步骤同时执行这两个操作。
#include <signal.h>int sigpromask(int how, const sigset_t *restrict set, sigset_t *restrict oset);/* 若成功则返回0,若出错则返回-1 */
若oset是非空指针,那么进程的当前信号屏蔽字通过oset返回。
若set是一个非空指针,则参数how指示如何修改当前信号屏蔽字。
如果set是空指针,则不改变该进程的信号屏蔽字,how的值也无意义。
在调用sigpromask后如果有任何未决的、不再阻塞的信号,则在sigpromask返回前,至少会将其中一个信号递送给该进程。
10.5 sigpending函数
sigpending函数返回信号集,其中的各个信号对于调用进程是阻塞的而不能递送,因而也一定是当前未决的。
#include <signal.h>int sigpending(sigset_t *set);/* 若成功则返回0,若出错则返回-1 */
10.5 sigaction函数
sigaction函数的功能是检查或修改与指定信号相关联的处理动作(或同时执行这两种操作)。
#include <signal.h>int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);/* 若成功则返回0,若出错则返回-1 */
参数signo是要检测或修改其具体动作的信号编号。
若act为空, 则要修改其动作。
若oact非空,则系统经由oact指针返回该信号的上一个动作。
struct sigaction {void (*sa_handler)(int); /* addr of signal handler *//* or SIG_IGN, or SIG_DFL */sigset_t sa_mask; /* additional signals to block */int sa_flags; /* signal options */void (*sa_sigaction)(int, siginfo_t *, void *);
}
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_t结构包含了信号产生原因的有关信息。
struct siginfo {int si_signo; /* signal number */int si_errno; /* if nonzero, errno value from <errno.h> */int si_code; /* additional info(depends on signal) */int si_pid; /* sending process ID */int si_uid; /* sending process real user ID */int *si_addr; /* address that caused the fault */int si_status; /* exit value or signal number */int si_band; /* band number for SIGPOLL *//* possibly other fields also */
};
下表列出了各种信号的si_code值。
10.6 sigsetjmp和siglongjmp函数
#include <setjmp.h>int sigsetjmp(sigjmp_buf env, int savemask);/* 若直接调用则返回0,若从siglongjmp调用返回则返回非0值 */int siglongjmp(sigjmp_buf env, int val);
10.7 sigsuspend函数
#include <signal.h>int sigsuspend(const sigset_t *sigmask);/* 返回值:-1,并将errno设置为EINTR */
10.7 abort函数
#include <stdlib.h>void abort(void);
是异常程序终止。
此函数将SIGABRT信号发送给调用进程。具体方法是raise(SIGABRT)。
10.7 其他
#include <signal.h>void psignal(int signo, const char *msg);/* 类似perror */
#include <string.h>char *strsignal(int signo);/* 类似strerror */
#include <signal.h>int sig2str(int signo, char *str);
int str2sig(const char *str, int* signop);/* 成功返回0,出错返回-1 *//* 它们出错时,并不设置errno */
这篇关于APUE——Chapter 10:信号的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!