赞
踩
对Linux来说,信号时软中断,许多重要的程序都需要处理信号。
信号为Linux提供了一种处理异步事件的方法。
比如:终端用户输入ctrl+c来中断程序,会通过信号机制停止一个程序。
信号概述: 1.信号的名字和编号 每个信号都有一个名字和编号,这些名字都以"SIG"开头,例如"SIGIO","SIGCHLD"等 等。 信号定义在signal.h头文件中,信号名都定义为正整数。 具体的信号名称可以使用kill -l来查看信号的名字以及序号,信号时从1开始编号的, 不存在0号信号。kill对于信号0有特殊意义。 2.信号的处理 信号的处理有三种方法: 忽略,捕捉和默认动作。 忽略信号:大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别 是SIGKILL和SIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方 法。如果忽略,那么这个进程就变成了没人能管理的进程,显然是内核设计者不希望 看到的场景。 捕捉信号:需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处 理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函 数,以此来实现某种信号的处理。 系统默认动作:对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号, 系统会自动执行。不过,对系统来说,大部分的吃力方式都比较粗暴,就是直接杀死 该进程。 具体的信号默认动作可以使用 man 7 signal 来查看系统的具体定义。 3.信号处理函数的注册------入门版:signal 高级版:sigaction 信号处理发送函数------入门版:kill 高级版:sigqueue
$:ps -aux|grep a.out-----------------查看a.out进程
$:kill -9 (进程ID) ------------------杀死进程
或$:kill -SIGKILL (进程ID)-----------杀死进程
对于信号而言,最大意义不是杀死信号,而是实现一些异步通讯手段。
入门: 重在动作,没有携带信息
signal原型:
typedef void(*sighandler_t)(int)---------函数指针
sighandler_t signal(int signum,sighandler_t handler);
int signum:信号编码
sighandler_t(结构体) handler:函数指针
kill原型:
int kill(pid_t pid,int sig);
pid:进程ID号
sig:信号编号
例:按Ctrl+c不退出 #include <signal.h> #include <stdio.h> void handler(int signum) { printf("get signum:%d\n",signum); // 打印信号的值 printf("never quit\n"); } int main() { signal(SIGINT,handler); //信号注册,捕捉信号 //signal(SIGINT,SIG_IGN); //忽略信号,按Ctrl+c后没有反应,但仍可以用指令杀死 while(1); return 0; } 运行结果: while(1):一直执行 按Ctrl+c出现: ^Cget signum:2 never quit ^Cget signum:2 never quit ^Cget signum:2 never quit ^Cget signum:2 never quit ^Cget signum:2 never quit 按Ctrl+x退出
通过软件编程来实现signal信号捕捉后对信号进行专配 信号处理dome #include <signal.h> #include <stdio.h> void handler(int signum) { printf("get signum:%d\n",signum); printf("never quit\n"); } int main() { signal(SIGINT,handler); while(1); return 0; } 信号发送dome #include <stdio.h> #include <signal.h> #include <sys/types.h> #include <stdlib.h> int main(int argc,char **argv) { int signum; int pid; signum = atoi(argv[1]); //因为是char **argv,所以要用atoi转成int pid = atoi(argv[2]); printf("signum:%d,pid:%d\n",signum,pid); kill(pid,signum); //信号发送 return 0; } 也可以用shell脚本的方式去做: char cmd[128] = {0}; sprintf(cmd,"kill -%d %d",signum,pid); system(cmd); 来显示打印信息 运行结果: 信号处理运行,信号发送要先得知信号处理的进程ID,通过(ps -aux|grep 运行程序名) 查看。然后发送信号,杀死进程:./a.out 9 4325
高级: 发送信号的同时带有信息 接收信号原型: #include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); struct sigaction { void (*sa_handler)(int); //信号处理程序,不接受额外数据,SIG_IGN 为忽 略,SIG_DFL 为默认动作 void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,能够接受额 外数据和sigqueue配合使用 sigset_t sa_mask;//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信 号阻塞字,信号捕捉函数返回之前恢复为原先的值。 int sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据 }; //回调函数句柄sa_handler、sa_sigaction只能任选其一 信号发送函数: #include <signal.h> int sigqueue(pid_t pid, int sig, const union sigval value); union sigval { int sival_int; void *sival_ptr; };
处理信号信息dome #include <signal.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> void handler(int signum, siginfo_t *info, void *context) { printf("get signum:%d\n",signum); if(context != NULL){ printf("get date:%d\n",info->si_int); printf("get date:%d\n",info->si_value.sival_int); printf("from:%d\n",info->si_pid); } } int main() { struct sigaction act; printf("pid = %d\n",getpid()); act.sa_sigaction = handler; act.sa_flags = SA_SIGINFO; sigaction(SIGUSR1,&act,NULL); while(1); return 0; } 首先用sigaction来注册信号,注册的时候第一个参数是我要收哪一个信号, 第二个参数是我收到这个信号后想要干什么,第三个参数是用来备份。 第二个参数是这么回事,我要接收信号就必须指定里面的flags这个参数,收 到信号以后去调用handler来处理信号,handler收到信号后吧信号的值打印 出来(signum),接着把内容(info)打印出来,内容是否有,取决于context, context非空的话,info就有内容,把info里面的si_int数据打印出来。 发送信号dome #include <signal.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> int main(int argc,char **argv) { int signum; int pid; signum = atoi(argv[1]); pid = atoi(argv[2]); union sigval value; value.sival_int = 999; sigqueue(pid,signum,value);-------value:联合体 printf("done\n"); return 0; }
运行结果:
详细教程,在此网站:Linux 信号.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。