本节主要学习信号和与信号相关的处理函数,后续还会更新。
http://blog.csdn.net/xiaoliangsky/article/details/40264151
一 信号
信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些行动。通常信号是由一个错误产生的。但它们还可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程。一个信号的产生叫生成,接收到一个信号叫捕获。
二 信号的种类
Signal Description
SIGABRT 由调用abort函数产生,进程非正常退出
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专用,进程超过资源限制的时候发送
三 信号相关的函数
1 signal函数
void (*signal(int sig, void (*func)(int)))(int);
signal是一个带有sig和func两个参数的函数,func是一个类型为void (*)(int)的函数指针。该函数返回一个与func相同类型的指针,指向先前指定信号处理函数的函数指针。准备捕获的信号的参数由sig给出,接收到的指定信号后要调用的函数由参数func给出。其实这个函数的使用是相当简单的,通过下面的例子就可以知道。注意信号处理函数的原型必须为void func(int),或者是下面的特殊值:
SIG_IGN:忽略信号
SIG_DFL:恢复信号的默认行为
这个函数常常可以用下面要将的sigaction函数替代。
2 sigaction
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
该函数与signal函数一样,用于设置与信号sig关联的动作,而oact如果不是空指针的话,就用它来保存原先对该信号的动作的位置,act则用于设置指定信号的动作。
参数结构体sigaction定义如下:
struct sigaction{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t*, void*);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
信号集sigset_t结构体:
typedef struct
{
unsigned long sig[_NSIG_WORDS];
}sigset_t;
信号处理函数可以采用void (*sa_handler)(int)或void (*sa_sigaction)(int, siginfo_t *, void *)。到底采用哪个要看sa_flags中是否设置了SA_SIGINFO位,如果设置了就采用void (*sa_sigaction)(int, siginfo_t *, void *),此时可以向处理函数发送附加信息;默认情况下采用void (*sa_handler)(int),此时只能向处理函数发送信号的数值。
sa_handler 此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
sa_mask 用来设置在处理该信号时暂时将sa_mask指定的信号集搁置。
sa_restorer 此参数没有使用。
sa_flags 用来设置信号处理的其他相关操作,下列的数值可用:
sa_flags 还可以设置其他标志:
SA_RESETHAND 当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
SA_RESTART 如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
SA_NODEFER 一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号。
返回值
执行成功则返回0,如果有错误则返回-1。
错误代码
EINVAL 参数signum 不合法, 或是企图拦截SIGKILL/SIGSTOPSIGKILL信号
EFAULT 参数act,oldact指针地址无法存取。
EINTR 此调用被中断
下面一个简单的例子,程序里面的sigemptyset、kill函数会在后面讲
action.c实例代码:
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> void sig_handler(int sig) { switch(sig) { case 23: printf("child : the signo is 23, hehe\n"); return; case 22: printf("father : hello wordl 22!\n"); return; } } int main() { struct sigaction act, oact; int status; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = sig_handler; sigaction(23, &act, &oact); sigaction(22, &act, &oact); pid_t pid, ppid; if (!(pid = fork())) { printf("child begin\n"); kill(getppid(), 22); sleep(3); printf("child over\n"); } else { printf("father begin\n"); kill(getpid(), 23); wait(&status); if (WIFSIGNALED(status)) { printf("child process receive siganl %d\n", WTERMSIG(status)); } printf("father over\n"); } return 0; }
http://blog.csdn.net/xiaoliangsky/article/details/40264151
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> #include <signal.h> void sig_handler(int signum) { switch(signum) { case SIGINT: printf("the signo is SIGINT %d received, hehe\n", SIGINT); return; case SIGCHLD: printf("the signo is SIGCHLD %d received, hihi!\n", SIGCHLD); return; case SIGUSR1: printf("the signo is SIGUSR1 %d received, hihi!\n", SIGUSR1); return; case SIGIO: printf("the signo is SIGIO %d received, hihi!\n", SIGIO); return; case SIGALRM: printf("the signo is SIGALRM %d received, hihi!\n", SIGALRM); return; default: printf("the signo %d is not processed\n", signum); return; } } int main() { int i; int status; pid_t pid; sigset_t set; sigset_t oldset; struct sigaction act; struct sigaction oldact; act.sa_flags = 0; act.sa_handler = sig_handler; sigemptyset(&act.sa_mask); sigaction(SIGINT, &act, &oldact); sigaction(SIGCHLD, &act, &oldact); sigaction(SIGUSR1, &act, &oldact); sigaction(SIGALRM, &act, &oldact); sigaction(SIGIO, &act, &oldact); sigemptyset(&set); sigaddset(&set, SIGINT); sigaddset(&set, SIGUSR1); if ((pid = fork()) < 0) { fprintf(stdout, "fork error\n"); exit(-1); } else if (pid > 0) { if (sigprocmask(SIG_BLOCK, &set, &oldset) < 0)//屏蔽信SINGINT、SIGUSR1 { fprintf(stdout, "sigprocmask error\n"); kill(pid, SIGKILL); exit(-1); } /* waitpid(pid, &status, 0); if (WIFSIGNALED(status)) { printf("child process receive siganl %d\n", WTERMSIG(status)); } */ pause();//接收SIGIO? pause();//接收SIGALRM? pause();//接收SIGCHLD? //pause(); //pause(); } else { sleep(1); kill(getppid(), SIGINT);//信号被屏蔽 sleep(1); kill(getppid(), SIGIO); sleep(1); kill(getppid(), SIGUSR1);//信号被屏蔽 sleep(1); kill(getppid(), SIGALRM); sleep(2); //子进程退出会发送一个SIGCHLD信号 } return 0; }
#include <unistd.h> #include <signal.h> #include <stdio.h> void sig_handler(int sig) { if (sig == SIGINT) printf("SIGINT sig\n"); else if (sig == SIGQUIT) printf("SIGQUIT sig\n"); else if (sig == SIGUSR1) printf("SIGUSR1 sig\n"); else if (sig == SIGUSR2) printf("SIGUSR2 sig\n"); else printf("SIGCHLD sig\n"); } int main() { int i; sigset_t new; sigset_t old; sigset_t wait; struct sigaction act; act.sa_handler = sig_handler; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGINT, &act, 0); sigaction(SIGQUIT, &act, 0); sigaction(SIGUSR1, &act, 0); sigaction(SIGUSR2, &act, 0); sigaction(SIGCHLD, &act, 0); sigemptyset(&new); sigaddset(&new, SIGINT); sigemptyset(&wait); sigaddset(&wait, SIGUSR1); sigaddset(&wait, SIGUSR2); sigprocmask(SIG_BLOCK, &new, &old); for (i=0; i < 90; ++i) { printf("%d\n", i); sleep(1); } sigsuspend(&wait); printf("After sigsuspend\n"); printf("yyyy\n"); if (-1 == sigprocmask(SIG_SETMASK, &old, NULL)) { perror("sigprocmask"); exit(-1); } for (i=0; i < 30; ++i) { printf("%d\n", i); sleep(1); } printf("xxxxx\n"); return 0; }
原文地址:http://blog.csdn.net/xiaoliangsky/article/details/40264151