Linux下信号处理(发送、捕获)

这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战

一、Linux下信号介绍

Linux下进行应用编程时,信号的处理必不可少。信号可以用于多进程间通信,查看当前系统支持的所有信号: kill -l

[wbyq@wbyq linux_c]$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) 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
复制代码

几个比较常用的信号:

  1. SIGINT 当用户按下了<Ctrl+C>时,用户终端向当前正在运行的进程发出此信号,默认动作为是终止当前进程。
  2. SIGQUIT 快捷键是<Ctrl+>,和SIGINT 一样默认动作结束当前进程.
  3. SIGSEGV 访问非法内存产生的信号,也就是经常遇到的段错误
  4. SIGALRM 定时器超时信号,比如闹钟的时间到达就会产生该信号.
  5. SIGIO 数据可读写信号,一般与驱动程序交互时,设备有数据可读,就会产生该信号,通知进程去读取数据。

Linux下应用层的信号与单片机裸机程序里中断类似,都可以设置处理函数.中断服务函数。 如果进程里不想使用信号的默认处理方式,可以自己捕获信号,然后再做相关处理。

比如: 当用户按下了<Ctrl+C>时,不想立即终止进程,可能还需要做一些善后工作,那么就可以自己捕获SIGINT信号,处理了内存释放、文件关闭、等等一些退出之前的清理工作之后,再退出。

信号的捕获函数如下:

#include <signal.h>
typedef void (*sighandler_t)(int);   //函数指针类型

sighandler_t signal(int signum, sighandler_t handler);
函数功能: 注册需要捕获的信号。
函数参数:
int signum  要捕获的信号。 Kill -l
sighandler_t handler :捕获到信号后,执行的函数。

复制代码

二、信号捕获、发送 案例

2.1 捕获Ctrl+C的信号

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>

/*
信号处理函数
*/
void sighandler_func(int sig)
{
    printf("捕获的信号:%d\n",sig);
}

int main(int argc,char **argv)
{
    //注册将要捕获的信号
    signal(SIGINT,sighandler_func);
    while(1)
    {

    }
    return 0;
}

复制代码

2.2 捕获段错误信号

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>
/*
信号处理函数
*/
void sighandler_func(int sig)
{
    printf("捕获的信号:%d\n",sig);
    exit(0); //结束进程
}

int main(int argc,char **argv)
{
    //注册将要捕获的信号
    signal(SIGSEGV,sighandler_func);

    int *p;
    *p=12345;  //给非法内存地址赋值

    while(1)
    {
        
    }
    return 0;
}

复制代码

2.3 通过kill命令给指定的进程发送信号

语法:

kill -s  <信号名称>  <进程的PID号>
kill -<信号名称>  <进程的PID号>
复制代码

示例:

[wbyq@wbyq linux_c]$ kill -s SIGINT 18365
[wbyq@wbyq linux_c]$ ps
  PID TTY          TIME CMD
 7481 pts/0    00:00:02 bash
18370 pts/0    00:02:49 a.out
18371 pts/0    00:03:28 a.out
18372 pts/0    00:02:46 a.out
18373 pts/0    00:02:36 a.out
18400 pts/0    00:00:00 ps
[1]   中断                  ./a.out
[wbyq@wbyq linux_c]$ kill -s 2 18370
[wbyq@wbyq linux_c]$ ps
  PID TTY          TIME CMD
 7481 pts/0    00:00:02 bash
18371 pts/0    00:03:39 a.out
18372 pts/0    00:02:56 a.out
18373 pts/0    00:02:47 a.out
18401 pts/0    00:00:00 ps
[2]   中断                  ./a.out
[wbyq@wbyq linux_c]$

[wbyq@wbyq linux_c]$ kill -2 18371

[wbyq@wbyq linux_c]$ kill -9 18372    //强制杀死指定的信号
[wbyq@wbyq linux_c]$ ps
  PID TTY          TIME CMD
 7481 pts/0    00:00:02 bash
18373 pts/0    00:05:31 a.out
18407 pts/0    00:00:00 ps
[4]-  已杀死               ./a.out
复制代码

查看当前进程的PID

查看后台运行的所有进程:
[wbyq@wbyq linux_c]$ ps    //查看当前终端后台进程
  PID TTY          TIME CMD
 7481 pts/0    00:00:02 bash
18365 pts/0    00:00:54 a.out
18370 pts/0    00:00:04 a.out
18371 pts/0    00:00:04 a.out
18372 pts/0    00:00:05 a.out
18373 pts/0    00:00:03 a.out
18374 pts/0    00:00:00 ps

[wbyq@wbyq linux_c]$ ps -aux   //查看当前系统所有的进程详细信息
wbyq     18365 65.1  0.0   1844   280 pts/0    R    09:19   1:33 ./a.out
wbyq     18370 35.9  0.0   1844   280 pts/0    R    09:20   0:34 ./a.out
wbyq     18371 34.9  0.0   1844   276 pts/0    R    09:20   0:32 ./a.out
wbyq     18372 44.7  0.0   1844   276 pts/0    R    09:20   0:41 ./a.out
wbyq     18373 34.4  0.0   1844   280 pts/0    R    09:20   0:32 ./a.out
wbyq     18375  5.0  0.0   6532  1048 pts/0    R+   09:21   0:00 ps -aux

[wbyq@wbyq linux_c]$ top   //动态查看当前系统的进程详细信息
程序后台运行的方式:
[wbyq@wbyq linux_c]$ ./a.out &
复制代码

2.4 通过代码给指定的进程发送信号

函数的用法与命令一样。

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
复制代码

おすすめ

転載: juejin.im/post/7035497819863531557