Linux 程序信号处理

    Linux下的信号名以SIG开头,如:SIGSEGV 段错误、SIGTERM 退出 等等,它们都在头文件<signal.h>中定义信号名和对应的值,并且信号的值都大于0。

    产生信号的原因:

1.硬件异常:除零出错、无效内存的引用,如SIGSEGV表示进程访问了无效的内存地址

2.软件发送的信号:如SIGPIPE表示进程尝试写入到没有阅读的管道(或socket)时,SIGALRM进程计时器到期

3.用户按下某些终端按键:如按下Ctrl+C,产生SIGINT信号,停止进程,按下Ctrl+Z产生SIGTSTR信号,挂起前台进程组

4.通过Kill命令向特定进程发送信号

5.通过raise函数,向自身发送信号

 

    对于信号的处理也有几种常见的方式:

1.可以忽略信号,除了SIGKILL和SIGSTOP外,其它的信号都可以由程序忽略

2.可以应用信号的默认操作,大多数信号的默认操作是结束进程,比如SIGTERM、SIGPIPE;SIGSEGV的默认操作是触发core dump,产生核心转储文件,便于进行debug

3.可以捕获信号, 比如当接收到SIGTERM时,对程序进行结束前的收尾工作,关闭文件描述符、socket,释放资源,删除临时文件;当接收到SIGCHLD时,调用waitpid获得子进程的PID,并获取它的退出码

 

    常见的信号、说明和默认操作:

SIGABRT                   异常终止                                  coredump

SIGALRM                   报警计时器超时                         终止

SIGBUS                     总线错误                                  coredump

SIGCANCEL               取消信号                                  忽略

SIGCHLD                   子进程状态改变                         忽略

SIGCLD                     SIGCHLD的别名                       忽略

SIGCONT                   继续已停止的进程                      忽略

SIGEMT                     仿真进程陷阱                            忽略

SIGFPE                      算术异常                                  coredump

SIGFREEZE               检查点冻结                                忽略

SIGHUP                    挂断                                         终止

SIGILL                      非法指令                                   coredump

SIGINT                     终端中断字符ctrl+c                     终止

SIGIO                       SIGPOLL的别名                         终止

SIGIOT                     SIGABRT的别名                         coredump

SIGKILL                    杀死进程                                   终止

SIGLOST                   资源丢失                                   终止

SIGPIPE                    写入没有阅读程序的管道              终止

SIGPOLL                   可轮询事件已经发生                    终止

SIGPROF                   记录计时器到期                          终止

SIGPWR                    电源失效或重新启动                    忽略

SIGQUIT                   终端退出字符                              coredump

SIGSEGV                   段错误                                       coredump

SIGSTOP                   停止                                          停止进程

SIGSYS                      存在错误的系统调用                    coredump

SIGTERM                    终止进程                                   终止

SIGTHAW                   检查点解冻                                忽略

SIGTRAP                    跟踪或断点陷阱                          coredump

SIGTSTP                    终端挂起符ctrl+z                        停止进程

SIGTTIN                     对控制台的TTY的后台读取            停止进程

SIGTTOU                    后台写入控制的TTY                     停止进程

SIGURG                      紧急套接字条件                          忽略

SIGUSR1                    用户自定义信号1                        终止

SIGUSR2                    用户自定义信号2                        终止

SIGVTALRM                虚拟计时器报警                          终止

SIGWAITING              并发的信号                                忽略

SIGWINCH                 终端窗口尺寸改变                       忽略

SIGXCPU                    超出cpu限制                             coredump

SIGFSZ                       超出文件尺寸限制                      coredump

SIGXRES                     超出资源控制                            忽略

 

    signal函数

    在<signal.h>中定义,

    void (*signal ( int sig,  void (*disp)(int) ) ) (int);

    其中参数sig为信号,disp为指定的信号部署。出错返回SIG_ERR

    其中disp可以是:

    1.常量SIG_IGN,忽略传入的信号,SIGKILL和SIGSTOP不能忽略

    2.常量SIG_DFL,将信号按其默认的处理方式运行。

    3.将捕获的信号交给disp定义的函数处理,SIGKILL和SIGSTOP不能生效

    使用signal函数的简单例子为:

#include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <signal.h> #include <syslog.h> #include <pthread.h> #include <stdlib.h> void signal_handler(int signo) { signal(signo, signal_handler); switch(signo) { case SIGHUP: //终端退出 syslog(LOG_NOTICE, "Process will exit, because tty is exit/n"); break; case SIGSEGV: //段错误,意味着指针所对应的地址是无效地址,没有物理内存对应该地址 syslog(LOG_ERR, "memory error/n"); exit(1); break; case SIGTERM: //程序自己退出,或shell里调用kill缺省该进程。该信号可以被阻塞,或被处理 //可以在这里做一些程序退出前的最后处理工作 syslog(LOG_NOTICE, "Process recieve SIGTERM/n"); exit(0); break; case SIGQUIT: //按下ctrl+ "/"产生,程序退出,并产生core文件 syslog(LOG_NOTICE, "Process recieve SIGQUIT/n"); exit(0); break; case SIGINT: //按下ctrl+c产生,程序终止 syslog(LOG_NOTICE, "Process recieve SIGINT/n"); exit(0); break; case SIGALRM: { //时钟定时信号 syslog(LOG_NOTICE, "Process recieve SIGALRM"); break; } case SIGCHLD: { //处理子进程退出 int *pidstat; pid_t pid; pid = waitpid(0, pidstat, WNOHANG); if (pid>0) syslog(LOG_WARNING, "child %d terminated/n", pid); syslog(LOG_NOTICE, "exit handle child process/n"); break; } default: syslog(LOG_WARNING, "%d signal unregister/n", signo); break; } } int main() { char thread_id[60]={0}; sprintf(thread_id, "pid:%d tid:%d", (int)getpid(), (int)pthread_self()); printf("%s/n",thread_id); printf("/n"); openlog(thread_id, LOG_PID, LOG_USER); char processName[260] = "ls"; signal(SIGHUP, &signal_handler); signal(SIGSEGV, &signal_handler); signal(SIGQUIT, &signal_handler); signal(SIGINT, &signal_handler); signal(SIGTERM, &signal_handler); signal(SIGALRM, &signal_handler); signal(SIGCHLD, &signal_handler); char* arg[] = { "ls", "-l", NULL }; pid_t child_pid; printf("The main program process ID is %d /n", (int)getpid()); child_pid = fork(); if(child_pid == -1) { printf("error, can not create child process, error is %s", strerror(errno)); return 1; } else if(child_pid != 0) { printf("this is the parent process, with id %d/n", (int)getpid() ); printf("the child's process id is %d/n", (int)child_pid); } else { execvp("ls", arg); printf("error is %s", strerror(errno)); printf("this is the child process, with id %d/n", (int)getpid() ); } while(1) { pause(); } return 0; }

 

   kill命令

    shell中的kill命令可以向进程中发送信号,比如

    $kill -INT 1377

    -INT是信号名,1377则是进程的pid

 

 

 

 

 

你可能感兴趣的:(thread,linux,socket,kill,终端,Signal)