linux下信号介绍及如何安装信号

1, 信号介绍

介绍信号前先复习一下中断,中断的意思就是比如你在写作业,忽然有人打电话过来了,你就得去接电话,这里电话铃声就是一种信号,你去接电话的动作就是中断处理程序。

信号是软件中断,它提供了一种处理异步事件的方法。每个信号都有一个名字,这些名字都是以SIG开头。 使用命令kill -l 可以查看当前系统支持的信号。
信号列举
信号值位于SIGRTMINSIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。

  • 下面是常用的信号
信号编号 信号名 信号说明 默认动作
2 SIGINT Ctrl+C按键终止程序运行的信号 程序终止
4 SIGILL 非法的指令 程序终止
7 SIGBUS 运行非本CPU相关编译器编译的程序 程序终止
9 SIGKILL 强制杀死程序信号,任何程序都不可以捕捉该信号 程序终止,不可被捕捉
10 SIGUSR1 用户自定义信号1 程序终止
11 SIGSEGV 段错误系统给程序发送的信号 程序终止
12 SIGUSR2 用户自定义信号2 程序终止
13 SIGPIPE 管道破裂信号 程序终止
14 SIGALRM alarm()系统调用发送的信号 程序终止
15 SIGTERM kill命令默认发送的信号,默认动作是终止信号 程序终止
17 SIGCHLD 子进程退出信号 忽略该信号

编号为0的信号有特殊用途,我们可以给某个进程发0号信号来判断该进程是否正在运行。在某个信号发生时,可以告诉内核按照下面三种方式进行处理:
1, 忽略此信号 //还是上面的例子,当听到手机铃声响起的时候,你可以选择忽略这个声音,假装没听见继续写作业
2,捕捉此信号 //当然你也可以选择接听这个电话1
3,执行系统默认动作。//比如你妈妈在早上出门前就跟你说下午打电话给你就代表她回家了,你不用接电话,而是去开门就行


kill 命令默认发 SIGTERM信号,如果SIGTERM被捕捉后,那么kill命令就不能停止该进程运行,
这时需要使用kill -9(SIGKILL)可以强制杀死某个进程。
在这里插入图片描述

  • 上面例子中我们创建了ping进程,首先我们按 ctrl+z,这是给进程发送了挂起的信号,我们发现当我们ps后,这个信号是杀不死这个进程的。
  • 后面我们kill 3219, 这其实只是发送了信号编号为15的默认信号 SIGTERM, 我么发现同样杀不死ping这个进程
  • 最后我们加了9号信号SIGKILL,因为这个信号是不可被捕捉的,最后成功杀死这个进程。

另外我们看看下面的例子进一步了解信号的概念
在这里插入图片描述

  • 上面我们按了 CTRL+c,ps 后发现ping命令被成功杀死,这里其实给进程发送了编号为2的SIGINT信号

2, 安装信号

信号是进程间通信机制中唯一的异步通信机制
signal()和sigaction()为信号安装函数
这两个函数的最大区别在于,经过sigaction安装的信号都能传递信息给信号处理函数,而经过signal安装的信号不能向信号处理函数传递信息。
简单说就是sigaction()比 signal()更加安全,信号不会丢失。所以我们一般使用sigaction(),而且它的功能更多。

  • 下面是两个函数的原型
    signal()
#include <signal.h>
typedef void (*sighandler_t)(int); 
sighandler_t    signal(int signum, sighandler_t handler); 
 //第一个参数是信号的编号,第二个是收到信后后需要执行的函数名称

下面是signal()函数的简单例子

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void    sig_handl(int signum)
{
        printf("catch siganl [%d]\n",signum);  //打印收到信号的编号
}



int main(int argc, char *argv[])
{
        signal(SIGINT, sig_handl);  //这里表示给程序安装了2号信号,即当按(ctrl+c)时程序就会去执行sig_handl函数里的内容
        while (1)
        {
         ;
        }
         return 0;
}

在这里插入图片描述

  • 因为程序安装了信号SIG_INT后执行sig_handl()函数,所以当我们按下ctrl +c 后并不能像之前杀死ping进程那样杀死进程了。

sigaction()

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数:
 signum:信号值
 act:信号的处理参数
 oldact:保存信号上次安装时的处理参数(备份的作用)
返回值:0(success),-1(error)

  • 下面是结构体
struct sigaction {
         void     (*sa_handler)(int); //信号处理函数
         void     (*sa_sigaction)(int, siginfo_t *, void *);
         sigset_t   sa_mask; //信号屏蔽集
         int        sa_flags; 
         void     (*sa_restorer)(void);// 已废弃
};
  • 下面给出和上面signal()相同功能的等价程序
void    sig_handl(int signum)
{
        printf("catch siganl [%d]\n",signum);
}



int main(int argc, char *argv[])
{
        struct      sigaction    sigact; //定义结构体

//下面三条语句初始化结构体
        sigemptyset(&sigact.sa_mask);
        sigact.sa_flags = 0;
        sigact.sa_handler = sig_handl;


        sigaction(SIGINT, &sigact, 0); //安装信号

        while (1)
        {
         ;
        }
         return 0;
}


发布了11 篇原创文章 · 获赞 22 · 访问量 2235

猜你喜欢

转载自blog.csdn.net/weixin_46027505/article/details/104530022
今日推荐