信号就是软件中断,信号提供一种处理异步事件的方法。
信号出现时按照下列方式处理:
1.忽略此信号,有两个信号不能忽略。
2.捕捉此信号,有两个信号不能被捕捉。
3.默认处理,少数默认处理是忽略,大部分默认处理是终止。
ctrl+D组合键,不是信号,只是EOF字符
linux中1-31为普通信号;34-64为实时信号。
trap-l
命令查看所有信号,64个
信号从1开始,没有0.
SIGHUP:终端接口检测到连接断开发出该信号,
SIGINT:ctrl+c,终端中断符,一般用来停止一个失去控制的进程。
SIGQUIT:ctrl+/,终端退出符,终止前台进程,可以重启该进程。
SIGILL:非法硬件指令,
SIGTRAP:硬件故障,
SIGABRT:进程异常终止,调用abort()库函数产生该信号。
SIGBUS:硬件故障,
SIGFPE:算数异常,除数为0或浮点溢出等产生,硬件检测然后通知内核。
SIGKILL:不能被忽略、不能被捕获,可以用来杀死任意进程。Kill-9
pid 或kill函数就是向进程发送该信号,杀死进程。
SIGUSR1:用户自定义信号。
SIGSEGV:无效的内存引用,硬件检测然后通知内核。
SIGUSR2:用户自定义信号。
SIGPIPE:在管道的读进程已终止后,一个进程写此管道时产生;当类型为SOCK_STREAM的套接字不再连接时进程写到套接字也产生该信号。
SIGALRM:闹钟信号,调用alarm()系统调用超时产生该信号。
SIGTERM:终止,当系统关机,init进程通常发送该信号给所有进程,等待一段时间,然后发送SIGKILL信号杀死所有进程。killpid命令默认向进程发出该信号。
SIGSTKFLT:协处理器栈故障,
SIGCHLD:子进程状态改变,当一个fork出来的子进程终止时发送一个该信号给父进程,默认忽略。
SIGCONT:使暂停进程继续,默认继续,否则忽略。
SIGSTOP:停止,不能被忽略、不能被捕获,默认暂停进程。
SIGTSTP:ctrl+z,终端停止符,停止在shell中运行的前台进程,返回作业编号,转到后台执行。
SIGTTIN:后台读控制tty,当一个后台进程组中的进程试图读其控制终端时终端产生此信号。
SIGTTOU:后台写至控制tty,当一个后台进程组中的进程试图写到其控制终端时产生该信号。
SIGURG:紧急情况,在网络连接上传来带外数据时产生,默认忽略。
SIGXCPU:超过cpu限制,
SIGXFSZ:超过文件长度限制,
SIGVTALRM:虚拟时间闹钟,调用setitimer()函数产生。
SIGPROF,梗概时间超时,
SIGWINCH:终端窗口大小改变产生,默认忽略。
SIGIO:指示一个异步IO事件,默认终止/忽略
SIGPWR:电源失效或重启,失效默认终止,重启默认忽略。
SIGSYS:无效系统调用,
##################################################
信号相关的系统调用
##################################################
#include<unistd.h>
intpause(void);
使调用进程挂起,直到捕捉到一个信号,返回-1.
#include<unistd.h>
unsignedint
alarm(unsignedint seconds);
seconds秒之后向进程发送一个SIGALRM信号;默认动作是终止调用alarm函数的进程,如果要捕捉需要在调用alarm函数之前捕捉。
一个进程只能有一个信号;
如果调用之前已经设置了闹钟,返回上一个闹钟剩余的时间;
如果调用之前设置了闹钟,seconds=0,返回上一个闹钟的剩余时间,但是取消上一个闹钟。
否则调用成功,返回0.
#include<sys/types.h>
#include<signal.h>
intkill(pid_tpid,
int sig);
往进程pid发送一个信号sig.
成功返回0,失败返回-1.
pid:
>0:将信号发送给进程ID=pid的进程
==0:将信号发送给与发送进程属于同一进程组的所有进程
<0:将信号发送给进程组ID=pid绝对值的所有进程
==-1:将信号发送给系统上所有进程。
#include<signal.h>
void(*signal(intsignum,
void (*handler)(int)))(int)
通过类型定义简化函数原型:
typdefvoid (*sighandler_t)(int);
sighandler_tsignal(intsignum,
sighandler_t handler);
返回之前的信号处理函数地址void*,该函数有一个int参数,出错返回SIG_ERR。
signum是信号的数值或名称。
Void(*handler)(int)是指向信号处理函数的指针,这个信号处理函数需要一个int参数。
handler也可以取下面值:
SIG_IGN:忽略该信号
SIG_DFL:按照默认处理信号
intsigprocmask(inthow,
const sigset_t *set, sigset_t *oldest);
信号屏蔽字函数,只适用于单线程的进程。
成功返回0,失败返回-1.
oldset如果非NULL,oldset返回进程当前的信号屏蔽字。
set如果非NULL,根据how来修改set中的信号屏蔽字。
set如果为NULL,信号屏蔽字不变。
how:
SIG_BLOCK:阻塞,SIGKILL和SIGSTOP不能阻塞。信号屏蔽字是当前信号屏蔽字和set的并集。设置阻塞后的信号进程不处理该信号,所以该信号是未决的。
SIG_UNBLOCK:解阻塞,信号屏蔽字是当前信号屏蔽字和set的补集的交集。
SIG_SETMASK:设置掩码,信号屏蔽字是set指向的信号集。
intsigpendig(sigset_t*set);
返回阻塞的不能递送的未决信号集,通过set返回。成功返回0,失败返回-1.
#include<signal.h>
intsigaction(intsginum,
const struct sigaction *act, struct sigaction *oldact);
检查或修改指定信号相关联的处理动作。
act非空,修改当前动作;oldact非空,返回上一个动作。
structsigaction{
void(*sa_handler)(int signo);
//普通信号处理函数/SIG_IGN/SIG_DFL
sigset_tsa_mask;
//设置为空集就不阻塞额外信号。
intsa_flags;
void(*sa_restorer)(void);
void(*sa_sigaction)(int, siginfo_t *, void *);
//当sa_flags=
SA_SIGINFO 用下面的指定实时信号处理函数.
};
sa_flags:
SA_NOCLDSTOP:
SA_NOCLDWAIT:
SA_NODEFER:
SA_ONSTACK:
SA_RESETHAND:
SA_RESTART:由此信号中断的系统调用会自动重启动。
SA_SIGINFO:提供附加信息,一个siginfo结构指针和一个指向进程上下文的标识符。
Structsiginfo {
intsi_signo;
intsi_code;
根据不同的信号取不同的值。
…...
};
intsigsuspend(constsigset_t
*mask);
总是返回-1,errno=EINTR。
将进程的信号屏蔽字设置为mask,在捕捉到一个信号,或发生一个会终止该进程的信号之前,该进程被挂起;如果捕捉到一个信号,且从该信号处理程序返回,则该函数返回,且进程的信号屏蔽字恢复为调用之前的。
#include<signal.h>
intsigwaitinfo(constsigset_t
*set, siginfo_t *info);
intsigtimedwait(constsigset_t
*set, siginfo_t *info, const struct timespec *timeout);
structtimespec {
longtv_sec;
longtv_nsec;
};
##################################################
信号相关库函数
##################################################
#include<stdlib.h>
voidabort(void);
使异常程序终止,向调用进程发送SIGABRT信号,该函数不理会进程的阻塞和忽略,可以捕获该信号进程善后工作,最终还是会终止进程。
#include<unistd.h>
unsignedint
sleep(unsignedint seconds);
使调用进程被挂起,满足下列两个条件之一就继续执行:
1.seconds指定的时间到,此时函数返回0.
2.调用进程捕捉到一个信号并从信号处理程序返回,此时函数返回剩余时间。
#include<signal.h>
intraise(intsig);
进程往自身发送信号sig。
成功返回0,失败返回-1.
#include<signal.h>
信号集函数,成功返回0,失败返回-1.
intsigemptyset(sigset_t*set);
将set指向的信号集置空,不包含任何信号。
intsigfillset(sigset_t*set);
将set指向的信号集填满,包括所有信号。
intsigaddset(sigset_t*set,
int signum);
向set指向的信号集中增加signum信号
intsigdelset(sigset_t*set,
int signum);
从set指向的信号集中删除signum信号
intsigismember(constsigset_t
*set, int signum);
测试signum是否是set指向的信号集中的信号;
真返回1,假返回0,失败返回-1.
#include<setjmp.h>
在信号处理程序中进行非局部转移应该使用下面两个函数。
intsigsetjmp(sigjmp_bufenv,
int savesigs);
直接调用返回0,从siglongjmp调用返回非0.
voidsiglongjmp(sigimp_bufenv,
int val);
由此跳转到sigsetjmp,并让其返回val。
#include<stdlib.h>
intsystem(constchar
*cmd);
posix要求system函数忽略SIGINT、SIGQUIT两个信号,阻塞SIGCHLD信号。
#include<signal.h>
voidpsignal(intsigno,
const char *msg);
类似于perror,输出到标准出错,msg后面自动加冒号和空格,后面是信号说明。
#include<string.h>
char*strsignal(intsigno);
类似于strerror,返回指向描述信号的字符串的指针。
#include<signal.h>
int
sigwait(constsigset_t *set, int *sig);
阻塞,等待set信号集中的某一个信号产生,然后返回,同时将该信号赋给sig。
#include<signal.h>
intsigqueue(pid_tpid,
int sig, const union sigval value);
unionsigval {
intsival_int;
void*sival_ptr;
};
未完待续......