试用一下CSDN博客的在线markdown编辑器,感觉还不错:)
信号是一种软件中断,用于提供异步事件处理机制。以下情形会产生信号:
对信号的处理方式有忽略(不能忽略SIGKILL、SIGSTOP和硬件异常)、默认动作(大部分都是终止进程,部分还会产生core)和设置自定义处理函数三种。
void (*signal(int signo, void (*func)(int))(int);
或者:
typedef void Sigfunc(int);
Sigfunc *signal(int, Sigfunc *);
#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0 默认动作
#define SIG_IGN (void (*)())1 无视信号
signal函数用于对信号signo设置信号函数func,返回之前的信号处理函数。signal函数在ISO C中定义,不涉及到多进程,定义够简明+含糊,所以基本上没什么用,一般用sigaction(后面介绍)
早期UNIX系统中信号机制是不可靠的,主要存在以下几个问题:
一些“低速”系统调用在信号发生时,可能会被中断,比如被阻塞的对管道或网络设备的读写操作、pause函数和某些ioctl函数。为了减少以下检查代码,操作系统对ioctl、read、write和wait等系统调用都会进行自动重启。
again:
if ((n = read(fd, buf, BUFFSIZE)) < 0) {
if (errno == EINTR)
goto again; /* just an interrupted system call */
}
下表总结了使用signal和sigaction函数时,各系统是否重置默认动作、能否阻塞信号和自动重启动被中断的系统调用等行为。
因为信号处理函数是异步的,信号处理时中断程序正在运行的方法,所以要求在信号处理函数中被调用的方法具有可重入性(reentrant)或异步信号安全性(async-signalsafe),很多函数都不具备可重入性,比如:
几个术语:
unsigned int alarm(unsigned int seconds);
int pause(void);
unsigned int sleep(unsigned int seconds)
alarm用于设置闹钟,超时后,内核产生SIGALARM信号,默认行为是终止进程。每个处理器只有一个闹钟时钟,调用alarm时,如果上次闹钟还没有超时,返回它剩余时间。pause函数挂起当前进程,直到信号生成并被处理后才返回。早期UNIX版本有用alarm和pause实现sleep,但alarm和pause调用存在竞争条件,如果alarm超时之后pause才被调用,进程可能被永久挂起,更好的方案是使用sigprocmask和sigsuspend。
因为各个系统信号数量都不同,比如Linux的信号数量已经超过40中,超出整型位数,所以POSIX定义了sigset_t用来代表信号集合,并提供了一系列函数用来操纵信号集。
#include
int sigemptyset(sigset_t *set);
int sigfillset(siget_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(setset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
int sigpending(sigset_t *set);
int sigsuspend(const sigset_t *sigmask);
其中:
int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);
struct sigactgion {
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_sigaction)(int siginfo_t *, void *);
}
sigaction函数非常强大,能够定义信号处理函数(sa_handler),同时设置屏蔽信号集(sa_mask),是否重启被中断的系统调用(sa_flags),更多信号和进程的信息(siginfo_t)。系统一般使用sigaction实现signal函数。
include "apue.h"
/* Reliable version of signal(), using POSIX sigaction(). */
Sigfunc *
signal(int signo, Sigfunc *func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
} else {
act.sa_flags |= SA_RESTART;
}
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}