=Start=
缘由:
在守护进程中需要实现根据收到的特定信号做特定操作的功能,所以在此学习整理一下Linux下信号处理的相关知识,方便以后查阅。
正文:
参考解答:
Linux下的信号处理有 signal() 和 sigaction() 函数。推荐使用符合 POSIX 标准的 sigaction() 函数。
signal() 函数的使用方法简单,但并不属于 POSIX 标准,在各类 UNIX 平台上的实现不尽相同,因此其用途受到了一定的限制。而 POSIX 标准定义的信号处理接口是 sigaction() 函数,其接口头文件及原型如下:
#include <signal.h> int sigaction( int signum, const struct sigaction *act, struct sigaction *oldact); |
◆ signum :要操作的信号。
◆ act :要设置的对信号的新处理方式。
◆ oldact :原来对信号的处理方式。
◆ 返回值 :0 表示成功,-1 表示有错误发生。
struct 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 ); }; |
在这个结构体中:
成员 sa_handler 是一个函数指针,其含义与 signal 函数中的信号处理函数类似。
成员 sa_sigaction 则是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。当 sa_flags 成员的值包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理函数。在某些系统中,成员 sa_handler 与 sa_sigaction 被放在联合体中,因此使用时不要同时设置。
成员 sa_mask 用来指定在信号处理函数执行期间需要被屏蔽的信号,特别是当某个信号被处理时,它自身会被自动放入进程的信号掩码,因此在信号处理函数执行期间这个信号不会再度发生。
成员 sa_flags 用于指定信号处理的行为,它可以是一下值的“按位或”组合:
◆ SA_RESTART:使被信号打断的系统调用自动重新发起。
◆ SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
◆ SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。
◆ SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。
◆ SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
◆ SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。
成员 re_restorer 则是一个已经废弃的数据域,不要使用。
下面以一个实际样例来说明sigaction()函数的使用:
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <errno.h> static void sig_usr( int signum) { if (signum == SIGUSR1) { printf( "SIGUSR1 received\n" ); } else if (signum == SIGUSR2) { printf( "SIGUSR2 received\n" ); } else { printf( "signal %d received\n" , signum); } } int main( void ) { char buf[ 512 ]; int n; /* sigset_t mask; sigfillset(&mask); //将参数 mask 信号集初始化,然后把所有的信号加入到此信号集里,在这里表示屏蔽所有信号 sigdelset(&mask, SIGUSR1); //删除set中的SIGUSR1信号,即——不屏蔽SIGUSR1信号 sigdelset(&mask, SIGUSR2); //不屏蔽SIGUSR2信号 sigprocmask(SIG_SETMASK, &mask, NULL); //参数SIG_SETMASK指定屏蔽mask中包含的信号集 */ struct sigaction sa_usr; sa_usr.sa_flags = 0 ; sa_usr.sa_handler = sig_usr; //信号处理函数 sigaction(SIGUSR1, &sa_usr, NULL); sigaction(SIGUSR2, &sa_usr, NULL); printf( "My PID is %d\n" , getpid()); while ( 1 ) { if ((n = read(STDIN_FILENO, buf, 511 )) == - 1 ) { if (errno == EINTR) { printf( "read is interrupted by signal\n" ); } } else { buf[n] = '\0' ; printf( "%d bytes read: %s\n" , n, buf); } } return 0 ; } |
在这个例子中使用 sigaction 函数为 SIGUSR1 和 SIGUSR2 信号注册了处理函数,然后从标准输入读入字符。程序运行后首先输出自己的 PID,如:
My PID is 5904
这时如果从另外一个终端向进程发送 SIGUSR1 或 SIGUSR2 信号,用类似如下的命令:
kill -USR1 5904
则程序将继续输出如下内容:
SIGUSR1 received
read is interrupted by signal
这说明用 sigaction 注册信号处理函数时,不会自动重新发起被信号打断的系统调用。如果需要自动重新发起,则要设置 SA_RESTART 标志,比如在上述代码中可以进行类似一下的设置:
sa_usr.sa_flags = SA_RESTART;
参考链接:
Linux 进程学习(四)—— sigaction 函数 #简单明了
http://www.cnblogs.com/wblyuyang/archive/2012/11/13/2768923.html
Linux下的信号详解及捕捉信号 #全面
http://www.jb51.net/article/90695.htm
如何忽略(除了 SIGKILL 和 SIGSTOP 之外的)所有信号
https://stackoverflow.com/questions/10046916/is-it-possible-to-ignore-all-signals
linux系统编程之信号(五):信号集操作函数,信号阻塞与未决
http://www.cnblogs.com/mickole/p/3191281.html
关于Linux信号的一切(All about Linux signals) #全面细致
http://www.linuxprogrammingblog.com/all-about-linux-signals?page=show
Linux 信号处理
https://fixatom.com/deal-with-linux-signals/
http://man7.org/linux/man-pages/man2/sigaction.2.html
http://man7.org/linux/man-pages/man3/sigfillset.3.html
http://man7.org/linux/man-pages/man2/sigprocmask.2.html
https://stackoverflow.com/questions/27227585/what-is-sigaddset-used-for
linux c学习笔记—-信号(sigaction,sigaddset,sigprocmask)
http://lobert.iteye.com/blog/1739021
C语言信号处理函数
http://c.biancheng.net/cpp/u/hs9/
Unix signal handling example in C, SIGINT, SIGALRM, SIGHUP…
https://gist.githubusercontent.com/aspyct/3462238/raw/3498fff4351518d8d40592015a9d3b5b9c22f7d5/signal.c
Signal Handling in C
https://stackoverflow.com/questions/2485028/signal-handling-in-c
24 Signal Handling
https://www.gnu.org/software/libc/manual/html_node/Signal-Handling.html
Linux C实践(1):不可忽略或捕捉的信号—SIGSTOP和SIGKILL
http://blog.csdn.net/madpointer/article/details/13091705
Linux进程间通信(四)—信号通信之信号发送捕捉kill()、raise()、alarm()、pause()及其基础实验
http://www.cnblogs.com/dyllove98/archive/2013/06/12/3132798.html
http://blog.csdn.net/mybelief321/article/details/9078193
Can signal be ignored (lost)?
https://unix.stackexchange.com/questions/181433/can-signal-be-ignored-lost
=END=
《 “Linux下C语言中的信号处理” 》 有 2 条评论
Linux signal那些事儿(1/2/3/4)
http://blog.chinaunix.net/uid-24774106-id-4061386.html
http://blog.chinaunix.net/uid-24774106-id-4064447.html
http://blog.chinaunix.net/uid-24774106-id-4065797.html
http://blog.chinaunix.net/uid-24774106-id-4084864.html
Linux使用KILL 0检测进程是否存在
https://typecodes.com/cseries/kill0checkprocessifexist.html
`
sending the signal 0 to a given PID just checks if any process with the given PID is running and you have the permission to send a signal to it.
kill函数中的形参sig是0的话,那么不会向pid进程发送任何信号,但是仍然会继续检测错误(进程ID或者进程组ID是否存在)。
信号值大于0的时候发送对应信号给某个进程,等于0的时候表示检测某个进程是否存在。
`
https://stackoverflow.com/questions/11012527/what-does-kill-0-pid-in-a-shell-script-do
https://serverfault.com/questions/436732/meaning-of-killall-0
https://unix.stackexchange.com/questions/169898/what-does-kill-0-do
https://unix.stackexchange.com/questions/17314/what-is-signal-0-in-a-trap-command