- 信号
signal
可以理解为由操作系统传给程序(进程)的事件,只是用来通知程序发生了什么事件,并不会传递给该进程任何数据. - 信号是一种中断,因为它可以改变程序的流程。当信号传递给进程时,进程将停下其正在执行的操作,并去处理或忽略该信号
异步事件
。
异步事件 - 查看信号的方式是一种处理异步事件的机制。
▶ 当程序通过 signal 函数捕获信号后,若 signal 函数第二参数为函数指针,则调用signal 函数的程序会阻塞(暂停在 signal 函数这句),直至异步线程(进入函数指针)return。程序将从暂停点恢复执行。
▶ 此外,进程之间可以互相通过系统调用kill发送软中断信号。
函数 signal
函数signal 用于捕获信号,可指定信号处理的方式,函数声明如下:
void (*signal(int sig, void (*func)(int)))(int);
第一个参数 sig 指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。
第二个参数描述了与信号关联的动作,下面将会对这三个参数进行讲解。
当程序收到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:
I. 默认处理:对信号进行该信号的系统默认处理,第二参数为 SIG_DFL。
II. 忽略信号:忽略该信号,第二参数为 SIG_IGN。
III. Function handler:指定处理函数,由该函数来处理,第二参数为 函数指针 。
若signal函数中第二参数(函数指针)中通过 raise发出与signal函数对应信号类型相同的信号。程序将在signal函数这成为死循环,自己发信号,自己捕获,进程暂停。
函数 raise
-
函数
raise
产生一个信号sig
,并向当前正在执行的程序发送信号sig
,其声明如下:int raise (int sig);
-
重点: 值得注意的是,raise发出的信号,可被当前进程中同类型型号的
signal
函数捕获。
处理函数:
static void sig_handler(int signo)
{
char Siglog[256] = { 0 };
if (SIGPIPE == signo)
{
fprintf(stderr, "\n\n\nwarning: ###########################################################################################SIGPIPE(%d) catched\n\n\n", signo);
return;
}
fprintf(stderr, "######################################################################################################Signal %d, exiting...\n", signo);
memset(Siglog,0,256);
sprintf(Siglog,"########################Signal %d, exiting...########################\n", signo);
syslog(LOG_DEBUG, "%s\n", Siglog);
lxLogwarn(3, Siglog);
mainDestory();
exit(EXIT_FAILURE);
}
static void signal_init(void)
{
/*忽略sigpipe(tcp 当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送SIGPIPE信号。)
为了防止客户端进程终止,而导致服务器进程被SIGPIPE信号终止,因此服务器程序要处理SIGPIPE信号*/
signal(SIGPIPE, SIG_IGN);
//总线错误
if (signal(SIGBUS, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGBUS!");
//数学相关的异常,如被0除,浮点溢出,等等
if (signal(SIGFPE, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGFPE!");
//session回话结束
if (signal(SIGHUP, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGHUP!");
//非法指令
if (signal(SIGILL, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGILL!");
//Ctrl+C
if (signal(SIGINT, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGINT!");
//if (signal(SIGPIPE, sig_handler) == SIG_ERR)
// fprintf(stderr, "Can't catch SIGPIPE!");
//类似sigint
if (signal(SIGQUIT, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGQUIT!");
//段错误 非法内存访问
if (signal(SIGSEGV, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGSEGV!");
//系统调用中参数错误
//if (signal(SIGSYS, sig_handler) == SIG_ERR)
// fprintf(stderr, "Can't catch SIGSYS!");
//程序结束
if (signal(SIGTERM, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGTERM!");
if (signal(SIGTRAP, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGTRAP!");
//由调用abort函数产生,进程非正常退出
if (signal(SIGABRT, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGTRAP!");
if (signal(SIGUSR1, sig_handler) == SIG_ERR)
fprintf(stderr, "Can't catch SIGTRAP!");
}
常用信号量:
Signal Description
SIGALRM 用alarm函数设置的timer超时或setitimer函数设置的interval timer超时
SIGBUS 某种特定的硬件异常,通常由内存访问引起
SIGCANCEL 由Solaris Thread Library内部使用,通常不会使用
SIGCHLD 进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略
SIGCONT 当被stop的进程恢复运行的时候,自动发送
SIGEMT 和实现相关的硬件异常
SIGFPE 数学相关的异常,如被0除,浮点溢出,等等
SIGFREEZE Solaris专用,Hiberate或者Suspended时候发送
SIGHUP 发送给具有Terminal的Controlling Process,当terminal 被disconnect时候发送
SIGILL 非法指令异常
SIGINFO BSD signal。由Status Key产生,通常是CTRL+T。发送给所有Foreground Group的进程
SIGINT 由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程
SIGIO 异步IO事件
SIGIOT 实现相关的硬件异常,一般对应SIGABRT
SIGKILL 无法处理和忽略。中止某个进程
SIGLWP 由Solaris Thread Libray内部使用
SIGPIPE 在reader中止之后写Pipe的时候发送
SIGPOLL 当某个事件发送给Pollable Device的时候发送
SIGPROF Setitimer指定的Profiling Interval Timer所产生
SIGPWR 和系统相关。和UPS相关。
SIGQUIT 输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程
SIGSEGV 非法内存访问
SIGSTKFLT Linux专用,数学协处理器的栈异常
SIGSTOP 中止进程。无法处理和忽略。
SIGSYS 非法系统调用
SIGTERM 请求中止进程,kill命令缺省发送
SIGTHAW Solaris专用,从Suspend恢复时候发送
SIGTRAP 实现相关的硬件异常。一般是调试异常
SIGTSTP Suspend Key,一般是Ctrl+Z。发送给所有Foreground Group的进程
SIGTTIN 当Background Group的进程尝试读取Terminal的时候发送
SIGTTOU 当Background Group的进程尝试写Terminal的时候发送
SIGURG 当out-of-band data接收的时候可能发送
SIGUSR1 用户自定义signal 1
SIGUSR2 用户自定义signal 2
SIGVTALRM setitimer函数设置的Virtual Interval Timer超时的时候
SIGWAITING Solaris Thread Library内部实现专用
SIGWINCH 当Terminal的窗口大小改变的时候,发送给Foreground Group的所有进程
SIGXCPU 当CPU时间限制超时的时候
SIGXFSZ 进程超过文件大小限制
SIGXRES Solaris专用,进程超过资源限制的时候发
函数 atexit
atexit()用来注册终止处理程序,当程序通过调用exit()或从main 中返回时被调用.终止处理程序执行的顺序和注册时的顺序是相反的,终止处理程序没有参数传递.同一个函数若注册多次,那它也会被调用多次.按POSIX.1-2001规定,至少可以注册32个终止处理程序,若想查看实际可以注册多少个终止处理程序,可以通过调用sysconf()函数获得.
当一个子进程是通过调用fork()函数产生时,它将继承父进程的所有终止处理程序.在成功调用exec系列函数后,所有的终止处理程序都会被删除.