信号的基本概念

信号是系统响应某个条件而产生的事件,进程接受到信号会执行相应的操作。(软中断信号,用来通知进程发生了异步事件)
信号是进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待信号的到达。
系统预先定义好的某些特定事件,信号可以被发送,也可以被接受,发送和接受的主题都是进程。

可靠信号以及不可靠信号

  • 不可靠信号:信号值小于SIGRTMIN(32)的信号,主要存在的问题是:进程每次处理信号后,就将对信号的响应设置为默认动作,在某些情况下,将导致信号的错误处理,用户如果不希望这样操作,就将在信号处理函数的结尾再一次调用signal()重新安装该信号,(总的俩说就是进程可能对信号作出错误的反应,以及信号可能丢失)
  • 可靠信号:在原有信号的机制上进行改进和扩充,这些信号支持派对,不会丢失,信号的发送和安装也出现了新函数(sigqueue和sigaction),早期的kill和signal依然被支持,信号值位于SIGRTMIN(32)和SIGRTMAX(63)之间的都称为可靠信号。

注意: 信号的可靠与不可靠只与信号值有关,与信号的发送和安装函数无关
signal和sigaction函数的主要区别就是:经过sigaction函数安装的信号都能传递信息给信号处理函数(对所有信号都成立),而经过signal函数安装的信号却不能向信号处理函数传递信息,对于信号发送函数也是一样的。

与信号有关的系统调用在“signal.h”头文件中有声明
常见信号的值,及对应的功能说明:

在Linux系统下定义了一些信号:
存储位置为:
/usr/include/bits/signum.h

理解信号:通知进程产生了某事件

忽略:有两个信号不可忽略:SIGKILL和SIGSTOP,
默认:linux对每一个信号对规定了默认操作,对实时信号(后32)的默认反应是进程中止。
自定义:定义信号处理函数,信号发生时,执行响应的信号处理函数。

信号的使用

信号发送

1、kill函数

将参数sig指定的信号传递给参数pid指定的进程,pid有如下几种情况:
①pid > 0:将信号传给进程识别码为pid的进程;
②pid = 0:将信号传给和目前进程相同进程组的所有进程;
③pid = -1:将信号广播给系统内的所有进程;
④pid < 0:将信号传给进程组识别码为pid绝对值的所有进程;

#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid,int sig)

执行成功返回0,执行失败返回-1;

2、alarm函数

用于设置信号传送闹钟,用来设置信号SIGALRM,在经过参数seconds指定的秒数后传送给目前的进程,若参数0,则之前设置的闹钟会被取消,并将剩下的时间返回。

#include<unistd.h>
unsigned int alarm(unsigned int seconds);

示例

int main()
{int i;signal(SIGALRM,handler);alarm(5);for(i = 1;i < 7;++i){printf("sleep %d...\n",i);sleep(1);}
}
自定义信号处理方式

如果信号要处理某一个信号,首先就要在进程中安装该信号。安装信号主要用来确定要处理哪个信号以及当信号被传递给进程时,将执行何种操作。

signal()

—— 不支持信号传递信息,主要用于前32中非实时信号的安装(有两个参数)

  • 默认SIG_DFL
  • 忽略SIG_IGN
  • 自定义void fun_sig(int sig)

我们通过帮助手册了解一下

  • 第一个参数是一个信号代号
  • 第二个参数是响应方式,是一个函数指针,返回值为void,参数为int


对于上面的程序,只有在按下ctrl+c后才会结束,否则将会一直执行下去,原因是给主程序发送了一个2号信号SIGINT,即终端终端信号,程序收到该信号后自动退出。
接下来,我们改变以下对于该信号的响应方式,我们收到该信号后打印一下这个信号的代号:
代码如下:

注意:这里的signal并没有执行,只是一个声明,只有当收到信号时才会调用
int sig就是信号的代号

此时我们按下Ctrl+c后发现是这样的:主程序并没有被打断,原因是:主程序是死循环是不会退出的,如果收到信号,当前程序被打断,内核帮助我们调用fun方法,再恢复执行while的函数体内容,因为我们已经改变了信号的响应方式,之前是按照默认方式响应的。
此时我们使用**Ctrl+\ **强制退出结束

下面展示对于该信号的三种操作方式的写法:

//默认
signal(SIGINT,SIG_DFL);
//忽略
signal(SIGINT,SIG_IGN);
//自定义
signal(SIGINT,sig_fun);

思考一下,如何使得第一次产生信号时是自定义,第二次又调用默认呢?
修改一下自定义函数即可:

于是:

siigaction()

—— 支持信号传递信息,主要用于前32中非实时信号的安装(有三个参数)
函数原型

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

根据参数signum指定的信号编号来设置该信号的处理函数,如果参数oldact不是NULL,则原来的信号处理方式将通过结构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()的参数handler相同,代表新的信号处理函数
  • sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置
  • sa_flags 用来设置信号处理的其他相关操作,下列的数值可用。
  • SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
  • SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
  • SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号

sa_sigaction 则是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。当 sa_flags 成员的值

包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理

函数。在某些系统中,成员 sa_handler 与 sa_sigaction 被放在联合体中,因此使用时不要同时设置。
sa_mask 成员用来指定在信号处理函数执行期间需要被屏蔽的信号,特别是当某个信号被处理时,它自身会被

自动放入进程的信号掩码,因此在信号处理函数执行期间这个信号不会再度发生。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>int main()
{struct sigaction newact,oldact;/* 设置信号忽略 */newact.sa_handler = SIG_IGN; //这个地方也可以是函数sigemptyset(&newact.sa_mask);newact.sa_flags = 0;int count = 0;pid_t pid = 0;sigaction(SIGINT,&newact,&oldact);//原来的备份到oldact里面pid = fork();if(pid == 0){while(1){printf("I'm child gaga.......\n");sleep(1);}return 0;}while(1){if(count++ > 3){sigaction(SIGINT,&oldact,NULL);  //备份回来printf("pid = %d\n",pid);kill(pid,SIGKILL); //父进程发信号,来杀死子进程}printf("I am father .......... hahaha\n");sleep(1);}return 0;
}

信号集操作

信号集被定义成一种数据类型:

typedef struct
{unsigned long sig[_NSIG_WORDS];
}sigset_t

x信号集用来描述信号的集合,Linux所支持的所有信号可以全部或部分地出现在信号集中,主要与信号阻塞相关的函数配合使用,以下是一些信号集操作定义的函数:

①sigemptyset函数

用于初始化信号集

int sigemptyset(sigset_t *set);       //将set所指信号集清0        成功:0;失败:-1
②sigfillset函数

用于将参数set初始化,将所有信号加入此信号集

int sigfillset(sigset_t *set);
③sigaddset函数

用于将参数signum代表的信号加入到参数set中

int sigaddset(sigset_t *set, int signum);
④sigdelset函数

用于从set信号集中删除signum信号

 int sigdelset(sigset_t *set, int signum);
⑥sigismember函数

用于测试某个信号是否已加入信号集中

int sigismember(const sigset_t *set, int signum);

用信号处理僵尸进程

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <assert.h>void fun(int sign)
{wait(NULL);
}
int main()
{signal(SIGCHILD,fun);//绑定信号与信号处理函数pid_t t = fork();assert(t!=-1);if(t == 0){printf("child start\n");sleep(2);printf("child over");}else{int i=0;while(i<100){sleep(1);i++;}}
}

例:运行程序,第一次接收到SIGINT信号,进程打印HelloWorld,第二次接受SIGINT信号,进程结束
方法:

  1. 第一次接受信号:fun
  2. 第二次接受信号前,将信号的响应方式修改为默认SIG_DFL
  3. 第二次接收信号,默认退出程序
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>void fun(int sign)
{printf("HelloWorld\n");//第一次接收到信号signal(SIGINT,SIG_DFL);//将信号响应方式恢复为默认,默认退出程序
}
int main()
{signal(SIGINT, fun);//程序启动时,绑定int i=0;while(i<100){sleep(1);printf("process running...\n");i++;}
}

Linux——信号及其使用相关推荐

  1. Linux shell 学习笔记(12)— linux 信号、后台运行脚本、作业控制、定时运行任务

    1. 处理信号 1.1 Linux 信号 常见的 Linux 信号如下表所示: 信号 值 描述 1 SIGHUP 挂起进程 2 SIGINT 终止进程 3 SIGQUIT 停止进程 9 SIGKILL ...

  2. linux信号(signal) 机制分析

    1       信号本质 软中断信号(signal,又简称为信号)用来通知进程发生了异步事件.在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的. ...

  3. linux 信号 core,Shell 信号发送与捕捉

    原标题:Shell 信号发送与捕捉 作者:李振良OK 1.Linux信号类型 信号(Signal):信号是在软件层次上对中断机制的一种模拟,通过给一个进程发送信号,执行相应的处理函数. 进程可以通过三 ...

  4. Linux信号 一 信号可靠性与分类

    开发SNMP的时候用到了Linux信号机制,总结了一下关于信号的知识. 信号是一种进程间通信手段,本质是一种软件中断,用来处理异步事件.信号机制是Unix家族里一个古老的通信机制.传统的信号机制有一些 ...

  5. linux信号使用,linux信号使用注意事项

    1.不要在信号处理函数中处理复杂的事情 2.信号处理函数中不能有互斥锁会造成死锁,可以用信号量替代 3.信号是置位方式实现,多次发送相同的信号可能只会收到一次 4.子进程具有继承父类信号屏蔽,不能在信 ...

  6. 非常好的一篇对linux信号(signal)的解析

    [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核对于信号的处理流程包括信号的触发/注册/执 ...

  7. 【Linux系统编程】Linux信号列表

    00. 目录 文章目录 00. 目录 01. Linux信号编号 02. 信号简介 03. 特殊信号 04. 附录 01. Linux信号编号 在 Linux 下,每个信号的名字都以字符 SIG 开头 ...

  8. linux信号以及core

    linux信号以及core 何为信号 信号(signal)用于通知进程发生了某种情况.进程有以下3种处理信号的方式: 忽略信号.有些信号表示硬件异常,例如,除以0或访问进程地址空间以外的存储单元等,因 ...

  9. linux 信号没有被处理方法,[计算机]Linux 信号signal处理机制.doc

    [计算机]Linux 信号signal处理机制 Linux 信号signal处理机制 信号是Linux编程中非常重要的部分,本文将详细介绍信号机制的基本概念.Linux对信号机制的大致实现方法.如何使 ...

  10. Linux信号实践(2) --信号分类

    信号分类 不可靠信号 Linux信号机制基本上是从UNIX系统中继承过来的.早期UNIX系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,它的主要问题是: 1.进程每次处理信号后,就将对信号 ...

最新文章

  1. Spark SQL 之SparkSession
  2. 微信小程序开发系列五:微信小程序中如何响应用户输入事件
  3. ios7之后的一些更改
  4. ajax数据显示,使用js通用模板
  5. Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class
  6. php最新版本6,PHP实用函数6
  7. 不是我吹!超级全面的权限系统设计方案面世了
  8. java安装教程_JAVA教程_Windows环境Java安装部署教程
  9. 夏昕ibatisiBATIS 2.0 开发指南配置文件说明
  10. 微信公众号创建与审核相关注意事项
  11. java画布canvas_画布(Canvas类)初探
  12. Julia Computing获得 2400 万美元融资,前 Snowflake CEO 加入董事会
  13. 金山云2018年Q4财报里的“去小米化”
  14. 常用数字电路模块:边沿检测电路
  15. 卸载win10自带的OneNote
  16. Django之爱鲜蜂项目开发 day06(一)
  17. 小区停车乱、停车难如何解决——走进小区的智慧停车
  18. Java解决主从数据库延迟问题_MySQL主从数据库同步延迟问题解决
  19. 浅谈spring中的设计模式(转)
  20. ValueError: No engine for filetype: ''

热门文章

  1. CLAMAV流检查接口
  2. Hello Jexus
  3. SQL SERVER 链接服务器Mysql
  4. G2自定义图例,数据更新时渲染问题。
  5. Docker部署Oracle11g
  6. C++信息学奥赛题目归类:2007-2018初赛普及组单项选择题
  7. 高清会议录播系统是什么,跟普通会议录播系统有什么区别?
  8. 笑死人不偿命的知乎沙雕问题排行榜
  9. Hadoop生态环境搭建
  10. R语言:用FMSB包做出漂亮雷达图