2022年Linux信号与信号处理 .pdf
《2022年Linux信号与信号处理 .pdf》由会员分享,可在线阅读,更多相关《2022年Linux信号与信号处理 .pdf(31页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、信号 (signal)是一种进程间通信机制,它给应用程序提供一种异步的软件中断,使应用程序有机会接受其他程序活终端发送的命令(即信号 )。应用程序收到信号后,有三种处理方式:忽略,默认,或捕捉。进程收到一个信号后,会检查对该信号的处理机制。如果是SIG_IGN ,就忽略该信号;如果是SIG_DFT ,则会采用系统默认的处理动作,通常是终止进程或忽略该信号;如果给该信号指定了一个处理函数(捕捉 ),则会中断当前进程正在执行的任务,转而去执行该信号的处理函数,返回后再继续执行被中断的任务。下面就来说说与信号有关的函数吧。最简单 signal 函数typedef void (*sighandler_
2、t) (int) sighandler_t signal(int signum, sighandler_t handler); 返回原信号处理函数,或SIG_ERR signal()是最简单的给进程安装信号处理器的函数,第一个参数指定信号,第二个参数为该信号指定一个处理函数。如下是一个最简单的处理信号的程序,它捕捉SIGUSR1 ,忽略SIGUSR2 ,按系统默认处理SIGINT , SIGUSR1和 SIGUSR2是 Linux 提供的用户定义信号,可用于任何应用程序。主程序什么都不干,只用pause()循环等待信号。例程 1 最简单的信号处理名师资料总结 - - -精品资料欢迎下载 - -
3、 - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 31 页 - - - - - - - - - static void pr_mask(const char * string) sigset_t procmask; sigprocmask(SIG_SETMASK, NULL, &procmask); printf(%s: , string); if(sigismember(&procmask, SIGINT) printf(SIGINT ); if(sigismember(&procmask, SIGUSR1) prin
4、tf(SIGUSR1 ); if(sigismember(&procmask, SIGUSR2) printf(SIGUSR2 ); if(sigismember(&procmask, SIGTERM) printf(SIGTERM ); if(sigismember(&procmask, SIGQUIT) printf(SIGQUIT ); printf(n); static void sigusr(int signum) pr_mask( “ int sigusr” ); if(signum = SIGUSR1) printf(“ SIGUSR1 receivedn” ); else if
5、(signum = SIGUSR2) printf(“ SIGUSR2 receivedn” ); else printf(“ signal %d receivedn” , signum); int main(void) if(signal(SIGUSR1, sig_usr) = SIG_ERR) printf(“en” ); exit(1); if(signal(SIGUSR2, SIG_IGN) = SIG_ERR) printf(“ error ignoring SIGUSR2n” ); exit(1); if(signal(SIGINT, SIG_DFT) = SIG_ERR) 名师资
6、料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 31 页 - - - - - - - - - printf(“ error setting SIGINT tn” ); exit(1); while(1) pause(); exit(0); 后台运行该程序,并用kill 发送信号给它。$./a.out & 1 3725 $kill -USR1 3725 in sigusr: SIGUSR1 SIGUSR1 received $kill -USR2 3725 1+ User def
7、ined signal 2 ./a.out 我们可以看到,Linux 系统对 SIGUSR2的默认动作是终止进程。中断与自动重启动名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 31 页 - - - - - - - - - 前面说过, 信号是一种软件中断机制,这就产生了一个问题:如果信号到来时进城正在执行某个低速系统调用,系统应该怎么处理?是暂时阻塞系统调用返回,在信号处理程序完成后继续没完成的系统调用呢,还是让系统调用出错返回,同时把errno 设置为EINTR ,让调
8、用者去做进一步的出错检查呢?用事实说话,让我们做一个试验先吧。下面的程序读取标准输入并把它输出到标准输出,在此期间,我们给进程发送SIGUSR1信号,以此来确定Linux 在收到信号后是如何对处理系统调用的。例程 2 信号与自动重启动的signal 版本int main(void) char bufBUFSIZ; int n; signal(SIGUSR1, sig_usr); while(1) if(n = read(STDIN_FILENO, buf, BUFSIZ) = -1) if(errno = EINTR) printf(“ read is interruptedn” ); els
9、e write(STDOUT_FILENO, buf, n); exit(0); 运行该程序,并从另一个终端给该进程发送信号SIGUSR1 。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 31 页 - - - - - - - - - $./a.out first line first line in sigusr: SIGUSR1 SIGUSR1 received second line second line in sigusr: SIGUSR1 SIGUSR1 re
10、ceived C 可见对由signal()函数安装的信号处理程序,系统默认会自动重启动被中断的系统调用,而不是让它出错返回,所以应用程序不必针对慢速系统调用的errno ,做 EINTR检查,这就是自动重启动机制。我们再来看另外一个例子,它使用另一个函数sigaction()来安装信号处理程序。sigaction()允许进程对信号进行更多的控制:例程 3 信号与自动重启动的sigaction 版本int main(void) char bufBUFSIZ; int n; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整
11、理 - - - - - - - 第 5 页,共 31 页 - - - - - - - - - struct sigaction sa_usr; sa_usr.flags = 0; /SA_RESART sa_usr.sa_handler = sig_usr; sigaction(SIGUSR1, &sa_usr, NULL); /signal(SIGUSR1, sig_usr); while(1) if(n = read(STDIN_FILENO, buf, BUFSIZ) = -1) if(errno = EINTR) printf(“ read is interruptedn” ); el
12、se write(STDOUT_FILENO, buf, n); exit(0); 此时再运行这个程序,并从另一终端给该进程发送信号SIGUSR1 ,我们会得到如下结果。$./a.out first line first line in sigusr: SIGUSR1 SIGUSR1 received read is interrupted second line second line in sigusr: SIGUSR1 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共
13、 31 页 - - - - - - - - - SIGUSR1 received read is interrupted C 由此我们可以得出,Linux 对 sigaction()的默认动作是不自动重启动被中断的系统调用,因此如果我们在使用sigaction()时需要自动重启动被中断的系统调用,就需要使用sigaction 的SA_RESTART 选项,见上例注释,关于sigaction(),下文会有更多的描述。这和UNIX环境高级编程中对Linux 信号处理的描述是一致的。可重入函数如前所述, 进程在收到信号并对其进行处理时,会暂时中断当前正在执行的指令序列,转而去执行信号处理程序。但是信
14、号的到来,往往是无法预测的,我们无法确定进程会在何时收到信号。如果进程在收到信号时正在执行malloc()调用,而此时捕捉到信号,进城就会转而去执行信号处理程序,而信号处理程序中又再次调用了malloc()函数,那结果将会怎样呢?进程的栈空间很可能就会受到破坏,从而产生无法预料的结果。所以有些函数是不能在信号处理程序中调用的,这些函数被称为不可重入函数,而那些允许在信号处理函数中调用的函数, 则称为可重入函数。 下表列出了Linux 系统中的可重入函数(摘自 UNIX 环境高级编程 ),对不在该表中的函数,信号处理函数中要慎用。表 1 可重入函数accept access 名师资料总结 - -
15、 -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 31 页 - - - - - - - - - aio_error aio_return aio_suspend alarm bind cfgetispeed cfgetospeed cfsetispeed cfsetospeed chdir chmod chown clock_gettime close connect creat dup dup2 execle execve _Exit & _exit fchmod 名师资料总结 - - -精
16、品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 31 页 - - - - - - - - - fchown fcntl fdatasync fork fpathconf fstat fsync ftruncate getegid geteuid getgid getgroups getpeername getpgrp getpid getppid getsockname getsockopt getuid kill link listen lseek 名师资料总结 - - -精品资料欢迎下载 -
17、- - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 31 页 - - - - - - - - - lstat mkdir mkfifo open pathconf pause pipe poll posix_trace_event pselect raise read readlink recv recvfrom recvmsg rename rmdir select sem_post send sendmsg 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - -
18、- 名师精心整理 - - - - - - - 第 10 页,共 31 页 - - - - - - - - - sendto setgid setpgid setsid setsockopt setuid shutdown sigaction sigaddset sigdelset sigemptyset sigfillset sigismember signal sigpause sigpending sigprocmask sigqueue sigset sigsuspend sleep socket 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - -
19、- - - - - - 名师精心整理 - - - - - - - 第 11 页,共 31 页 - - - - - - - - - socketpair stat symlink sysconf tcdrain tcflow tcflush tcgetattr tcgetpgrp tcsendbreak tcsetattr tcsetpgrp time timer_getoverrun timer_gettime timer_settime times umask uname unlink utime wait waitpid 名师资料总结 - - -精品资料欢迎下载 - - - - - - -
20、 - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 31 页 - - - - - - - - - write 发送信号的kill 和 raise 函数int kill(pid_t pid, int sig); int raise(int sig); kill()发送信号给指定进程,raise()发送信号给进程本身。对kill()的 pid,有如下描述:pid 0 将信号发送给ID 为 pid 的进程pid = 0 将信号发送给与发送进程属于同意个进程组的所有进程pid si_signo); printf(si_errno: %dn, inf
21、o-si_errno); printf(si_code: %dn, info-si_code); printf(si_pid: %dn, info-si_pid); printf(si_uid: %dn, info-si_uid); int main(void) 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 21 页,共 31 页 - - - - - - - - - struct sigaction act_usr1; struct sigaction act_usr2; sigs
22、et_t mask; act_usr1.sa_flags = SA_SIGINFO; /act_usr1.sa_handler = sigusr; sigemptyset(&act_usr1.sa_mask); act_usr1.sa_sigaction = handler; sigaction(SIGUSR1, &act_usr1, NULL); act_usr2.sa_flags = 0; act_usr2.sa_handler = sig_usr2; sigemptyset(&act_usr2.sa_mask); sigaction(SIGUSR2, &act_usr2, NULL);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 2022年Linux信号与信号处理 2022 Linux 信号 处理
限制150内