> 文章列表 > 信号、以及安装信号signal()与sigaction()函数讲解(实例代码)

信号、以及安装信号signal()与sigaction()函数讲解(实例代码)

信号、以及安装信号signal()与sigaction()函数讲解(实例代码)

文章目录

    • 一、信号
    • 二、signal()-安装信号函数
      • (1)函数原型
      • (2)代码测试
    • 三、sigaction()-安装信号函数
      • (1)函数原型
      • (2)代码测试

一、信号

信号是很短的信息,可以被发送到一个进程或者一组进程。发送给进程唯一信息通常是一个数,以此来标识信号。在标准信号中,对参数、消息或者其他的相随信息没有给予关注。

首先我们来了解一下Linux下的信号机制。

Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,信号值小于SIGRTMIN的信号都是不可靠信号。这就是"不可靠信号"的来源,它的主要问题是信号可能丢失。随着时间的发展,实践证明了有必要对信号的原始机制加以改进和扩充。由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为可靠信号,这些信号支持排队,不会丢失。我们可以使用 kill -l 命令查看当前系统支持的信号,需要注意的是不同的系统支持的信号是不一样的:

wangdengtao@wangdengtao-virtual-machine:~/wangdengtao$ kill -l1) SIGHUP	 	 2) SIGINT		 3) SIGQUIT		 4) SIGILL		 5) SIGTRAP6) SIGABRT		 7) SIGBUS		 8) SIGFPE		 9) SIGKILL		10) SIGUSR1
11) SIGSEGV		12) SIGUSR2		13) SIGPIPE		14) SIGALRM		15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD		18) SIGCONT		19) SIGSTOP		20) SIGTSTP
21) SIGTTIN		22) SIGTTOU		23) SIGURG		24) SIGXCPU		25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF		28) SIGWINCH	29) SIGIO		30) SIGPWR
31) SIGSYS		34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX

用的比较多的,需要知道的:

使用信号一般有两个目的:

  • 让进程知道已经发生了一个特定的事件;
  • 强迫进程执行它自己代码中的信号处理程序。

信号值位于SIGRTMINSIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。对于目前linux的两个信号安装函数:==signal()sigaction()==来说,它们都不能把SIGRTMIN以前的信号变成可靠信号(都不支持排队,仍有可能丢失,仍然是不可靠信号),而且对SIGRTMIN以后的信号都支持排队。这两个函数的最大区别在于,经过sigaction安装的信号都能传递信息给信号处理函数,而经过signal安装的信号不能向信号处理函数传递信息。对于信号发送函数来说也是一样的。

我们常用到的信号:
在这里插入图片描述


二、signal()-安装信号函数

(1)函数原型

Linux下可以用signal()信号安装的函数, 其中signal()函数的原型如下:

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
  • 第一个参数指定信号的值,
  • 第二个参数指定针对前面信号值的处理,可以忽略该信号(参数设为SIG_IGN);可以采用系统默认方式处理信号(参数设为SIG_DFL);也可以自己实现处理方式(参数指定一个函数地址)。

(2)代码测试

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>int g_sigstop = 0;void signal_stop(int signum)
{if(SIGTERM == signum){printf("SIGTERM signal detected\\n");}else if(SIGALRM == signum){printf("SIGALRM signal detected\\n");g_sigstop = 1;}
}void signal_code(int signum)
{if(SIGINT == signum){printf("SIGINT(CTRL+C) signal\\n");}else if(SIGSEGV == signum){printf("SIGSEGV signal detected\\n");exit(-1);}
}int main(int argc, char *argv[])
{char              *ptr = NULL;signal(SIGTERM, signal_stop);//kill命令终止signal(SIGALRM, signal_stop);//alarm()signal(SIGSEGV, signal_code);//指针非法操作内存问题signal(SIGINT, signal_code);//指针非法操作内存问题printf("Program start running for 20 seconds...\\n");alarm(20);while(!g_sigstop){;}printf("Program start stop running...\\n");printf("Invalid pointer operator will raise SIGSEGV signal\\n");/*这是非法地使用了指针,报错段错误,于是会触发SIGSEGV信号,就会打印相关的调用函数*/*ptr = 'h';return 0;
}

中间运行的二十秒可以使用CTRL+C来验证SIGINT信号。我们打开新的终端执行killall signal命令可以看到SIGTERM执行结果:

wangdengtao@wangdengtao-virtual-machine:~/wangdengtao$ ./signal 
Program start running for 20 seconds...
SIGTERM signal detected
SIGTERM signal detected
SIGTERM signal detected
SIGTERM signal detected
^CSIGINT(CTRL+C) signal
^CSIGINT(CTRL+C) signal
^CSIGINT(CTRL+C) signal
^CSIGINT(CTRL+C) signal
^CSIGINT(CTRL+C) signal
^CSIGINT(CTRL+C) signal
^CSIGINT(CTRL+C) signal
SIGALRM signal detected
Program start stop running...
Invalid pointer operator will raise SIGSEGV signal
SIGSEGV signal detected

三、sigaction()-安装信号函数

(1)函数原型

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

(2)代码测试

结合上面的代码进行 sigaction() 信号安装函数的测试:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>int g_sigstop = 0;void signal_stop(int signum)
{if(SIGTERM == signum){printf("SIGTERM signal detected\\n");}else if(SIGALRM == signum){printf("SIGALRM signal detected\\n");g_sigstop = 1;}
}void signal_code(int signum)
{if(SIGBUS == signum){printf("SIGBUS signal detected\\n");}else if(SIGILL == signum){printf("SIGILL signal detected\\n");}else if(SIGSEGV == signum){printf("SIGSEGV signal detected\\n");}exit(-1);
}void signal_user(int signum)
{if(SIGUSR1 == signum){printf("SIGUSR1 signal detected\\n");}else if(SIGUSR2 == signum){printf("SIGUSR2 signal detected\\n");}g_sigstop = 1;
}
int main(int argc, char *argv[])
{char              *ptr = NULL;struct sigaction  sigact,sigign;signal(SIGTERM, signal_stop);//kill命令终止signal(SIGALRM, signal_stop);//alarm()signal(SIGSEGV, signal_code);//指针非法操作内存问题/*用户自定义信号,收到之后执行signal_user函数*/sigemptyset(&sigact.sa_mask);sigact.sa_flags = 0;sigact.sa_handler = signal_user;/*如果是SIGINT(ctrl+z)信号就忽略*/sigemptyset(&sigign.sa_mask);sigign.sa_flags = 0;sigign.sa_handler = SIG_IGN;sigaction(SIGINT, &sigign, 0);sigaction(SIGUSR1, &sigact, 0);sigaction(SIGUSR2, &sigact, 0);printf("Program start running for 20 seconds...\\n");alarm(20);while(!g_sigstop){;}printf("Program start stop running...\\n");printf("Invalid pointer operator will raise SIGSEGV signal\\n");*ptr = 'h';return 0;
}

我们的SIGINT信号被忽视了,我们的KILL信号也接收到了:

wangdengtao@wangdengtao-virtual-machine:~/wangdengtao$ ./sigaction 
Program start running for 20 seconds...
^C^C^C^C^CSIGTERM signal detected
SIGTERM signal detected
SIGTERM signal detected
SIGALRM signal detected
Program start stop running...
Invalid pointer operator will raise SIGSEGV signal
SIGSEGV signal detected