概述
1、什么是信号
- 信号是一种内容受限的进程间通信机制。
- 信号是一种软件中断,是异步的。
- 信号就是int型的数字编号。
2、产生信号的四种场景
- 中断按下按键,比如ctrl+c
- 内核给应用程序发,比如访问无效内存、硬件故障等
- 使用kill命令
- 软件在满足某种条件的时候,比如alarm时间到了。
3、信号的三种处理方式
- 忽略信号:除了SIGKILL和SIGSTOP,都是可以忽略的或者被捕获
- 捕获信号:使用自定义函数处理信号
- 默认处理:包括忽略、终止、终止+core
常见的信号
- SIGINT:ctrl+c时候,内核给每个前台进程发送这个信号
- SIGABRT:调用abort函数,让进程异常终止
- SIGPOLL、SIGIO:异步IO事件会用到
- SIGKILL:杀死进程,并且信号不能被忽略
- SIGSEGV:无效的内存访问时,内核会发出这个信号给应用程序
- SIGPIPE:管道和socket会用到
- SIGALARM:alarm会用到
- SIGTERM:kill命令发送的默认信号
- SIGCHLD:子进程停止时内核给父进程发送这个信号
旧注册信号处理函数:signal
signal可以注册信号处理函数,但是一致性比较差,现在推荐使用sigaction。
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
sighandler_t:信号处理函数的函数模板,传递的参数是信号值
signum:信号值
handler:这个信号发生的时候,由哪个信号处理函数来处理。
SIG_IGN:忽略信号
SIG_DEF:使用默认的方式处理这个信号
自定义函数:使用自定义函数处理这个信号
返回值:成功,返回这个信号之前绑定的函数地址;失败返回SIG_ERR,同时置上errno。
SIG_ERR、SIG_IGN和SIG_DEF宏的定义,其实就是把常数强制类型转化成__sighandler_t函数指针:
less /usr/include/bits/signum.h
#define SIG_ERR ((__sighandler_t) -1) /* Error return. */
#define SIG_DFL ((__sighandler_t) 0) /* Default action. */
#define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */
新注册信号处理函数: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
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
signum:需要捕获的信号值
act:如果act非空,那么使用act->sa_handler指向的函数来处理这个信号,如果act可以为空,这个时候不会修改这个信号的处理函数,一般用于使用oldact来获取信号当前处理函数。
oldact:如果oldact非空,那么oldact指向这个信号之前的处理函数,如果oldact为空,那么表示不关注老的处理函数。
sa_mask:信号处理函数被执行的过程中,哪些信号被阻塞,直到执行完了之后再捕获这些信号
返回值:成功,返回0,失败返回-1,并且置上errno。
信号集的处理
信号集一般和struct sigaction配合使用,比如使用sigaction捕获信号的时候,希望把其他的好几个信号阻塞,等被捕获的信号处理完了之后,再恢复其他信号的处理,就可以使用信号集的处理函数来指定哪些信号被阻塞。
清空信号集:sigemptyset
sigemptyset把信号集里清空。
#include <signal.h>
int sigemptyset(sigset_t *set);
set:信号集
返回值:成功,返回0,失败,返回-1,同时置上errno
填满信号集:sigfillset
sigfillset所有的信号都加入到信号集当中。
#include <signal.h>
int sigfillset(sigset_t *set);
set:信号集
返回值:成功,返回0,失败,返回-1,同时置上errno
添加一个信号:sigaddset
sigaddset把某一个信号加入到信号集当中。
#include <signal.h>
int sigaddset(sigset_t *set, int signum);
set:信号集
signum:被添加的信号
返回值:成功,返回0,失败,返回-1,同时置上errno
删除一个信号:sigdelset
sigdelset把某一个信号从信号集中删除。
#include <signal.h>
int sigdelset(sigset_t *set, int signum);
set:信号集
signum:被添加的信号
返回值:成功,返回0,失败,返回-1,同时置上errno
判断信号是否在信号集中:sigismember
sigismember判断一个信号是否在信号集中。
#include <signal.h>
int sigismember(const sigset_t *set, int signum);
set:信号集
signum:待判断的信号
返回值:如果在信号集中,返回1,如果不在,返回0,如果出错,返回-1,同时置上errno
代码实例
捕获SIGHUP的同时,阻塞SIGINT:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
void sig_handler(int sig)
{
if (sig != SIGHUP) {
printf("sig %d is not SIGHUP");
return;
}
int i = 0;
for(i = 0; i < 10; i ++) {
printf("%s\n", __func__);
sleep(1);
}
return;
}
int
main(int argc, char **argv)
{
int i;
struct sigaction sact;
memset(&sact, 0, sizeof(struct sigaction));
sact.sa_handler = sig_handler;
sigemptyset(&(sact.sa_mask));
sigaddset(&sact.sa_mask, SIGINT);
sact.sa_flags = 0;
if (sigaction(SIGHUP, &sact, NULL) < 0) {
perror("sigaction:");
return -1;
}
for(i = 0; i < 10; i++) {
printf("wait signal, pid: %d\n", getpid());
sleep(1);
}
return 0;
}
版权声明:本文为a3876247995原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。