• linux信号的简单介绍
  • 信号的捕捉和处理
  • 信号处理函数的返回
  • 信号的发送
  • 信号的屏蔽

一:linux信号的简单介绍。

信号提供给我们一种异步处理事件的方法,由于进程之间彼此的地址空间是独立的,所以进程之间的通信就需要特殊的机制,而信号是进程之间唯一的异步通信方式。我们平时可以接触到的信号来源一般有:用户从键盘键入、一些硬件的异常、用户使用kill命令或者函数发送或者当系统检测到某种软件已经具有发出信号的条件(比如alarm或settimer设置的定时器超时时将生成SIGALRAM信号),linux下的信号种类有60多种,我们可以输入下面的命令查看:

$ kill -l

其中1~31为不可靠信号(可能会丢失,信号不支持排队),33~64为可靠信号,也叫做实时信号。在linux中,当导致信号的事件发生时,内核就会产生一个信号,信号产生后,内核通常会在进程表中设置某种形式的标志,即内核向一个进程递送了一个信号,信号产生和递送之间的时间间隔叫做“信号未决”。我们用户在产生信号之后可以要求进程对信号做出以下处理,例如捕捉信号,处理信号,忽略信号等。

二:信号的捕捉和处理。

1:signal()函数

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

这个定义等价于:

void(*signal(int signum,void(*)(int)))(int)

signal函数的第一个参数是即将要处理的信号的编号,第二个参数是一个指向函数的指针,此函数为我们的信号处理函数,它是一个返回值为void,参数为int的函数。

2:sigaction()函数

int sigaction(int signum(指定的信号), const struct sigaction *act(若非空,则为指定信号设置新的处理函数), struct sigaction *oldact(若非空,则存储旧的信号处理函数));

可以说signal函数是sigaction函数的简化版,因为struct sigaction act这个结构体中除了信号处理函数之外,我们还可以指定一些其他的信息,比如一般情况下我们在一个信号处理函数没有返回的时候是默认阻塞此信号的,但是我们可以通过设置act中的sa_flags = SA_NOMASK来设置信号的状态为在信号处理函数结束之前允许再次递送。

3:pause()函数

int pause(void);

pause函数的作用是将当前的进程挂起,等待任意一个信号中断。下面这个程序先调用pause然后从右边的shell发送信号,一旦收到信号,就会结束进程,下面的代码不会执行。

三:信号处理函数的返回

信号处理函数可以自己正常返回,也可以调用下面四个函数返回

1:setjmp和longjmp函数

int setjmp(jmp_buf env);

env:一个全局变量,通过调用setjmp将目前的栈状态信息保存,当调用longjmp时能用来恢复栈状态的信息

int longjmp(jmp_buf env, int val);

val:此参数是setjmp的返回值。

两个函数配合使用,但是有缺点,因为我们在信号处理函数中会自动阻塞正在被处理的信号,如果我们调用longjmp函数返回,是不会解除阻塞的,即被处理过的信号会一直阻塞着,需要我们手动去处理,为了避免这种手动处理,我们会用到下面这两个函数:

int sigsetjmp(sigjmp_buf env, int savesigs);

savesigs:只要它的值非0,则sigsetjmp会在env中保存当前信号的屏蔽字,在调用siglongjmp时,会从其中恢复保存的信号屏蔽字。

void siglongjmp(sigjmp_buf env, int val);

四:信号的发送

1:kill函数:

int kill(pid_t pid, int sig);

pid:>0 : pid表示某一个进程的pid, =0 :给当前进程所属组中的所有进程发送, =-1 :把信号广播给系统中除了自己和init进程 <-1 :把信号发送给属于进程组-pid的所有进程。

注意:只有root用户才可以给所有的进程发送信号,普通用户只能同一组或者给自己发送信号。

2:raise()函数

int raise(int sig);

sig:表示要发送的信号,给调用raise的进程发送。

3:sigqueue()函数

int sigqueue(pid_t pid,int sig,const union sigval value);

union sigval //此共用体的第一个元素与siginfo_t中si_int 一样

{

int sival_int;

void *sival_ptr;

};

sigqueue函数是alarm函数的加强版本,它的第三个参数可以和sigaction配合使用在两个进程之间传输数据,即我们在信号发送的时候让它的第三个参数value.sival_int携带数值,而后我们在sigaction中将sa_flags = SA_SIGINFO,则信号处理函数由三参数的sa_sigaction指定,此时siginfo_t 结构体中的成员si_int 就可以接受发送的数据。

4:alarm()函数

unsigned int alarm(unsigned int seconds);

alarm函数设置定时器,时间过了就会给调用进程发送信号SIGALRM信号,只会发送一次,如果需要多次,则需要多次调用。

下面程序简单介绍了ping命令的实现:

#include<stdio.h>
#include<signal.h>
#include<unistd.h> //此程序的目的在于模拟ping的工作原理, void handler_sigalarm(int signo)
{
printf("send a request packet\n");
alarm(1); //每隔一秒就会给进程发送一个SIGALRM信号
} int main(int argc,char *argv[])
{
signal(SIGALRM,handler_sigalarm); //signal 函数在此处理SIGALRM, raise(SIGALRM); //首先由raise函数给进程发送一个SIGALRM信号,signal函数捕获到发送的信号,进入信号处理函数,再次由alarm函数每隔一秒发送一个SIGALRM信号
while(1); return 0;
}

五:信号的屏蔽

1:信号集:linux下信号有60多种,POSIX标准定义了数据类型sigset_t来表示信号集,并且定义了许多函数来操作信号集。

  int sigemptyset(sigset_t *set);  //初始化信号集,使其为空
int sigfillset(sigset_t *set); //初始化信号集,使其包括所有信号
int sigaddset(sigset_t *set, int signum); //添加一个信号到信号集
int sigdelset(sigset_t *set, int signum); //删除一个信号
int sigismember(const sigset_t *set, int signum); //判断一个信号是否在信号集中

2:信号屏蔽:也可以说信号阻塞

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); //信号屏蔽

how:设置相关信号屏蔽码的操作。

set :非空的话为信号设置新的屏蔽码

oldset:非空的话将原来的信号屏蔽码返回

int sigpending(sigset_t *set); //获取当前未决信号集,注意未决队列里面的信号如果没有被处理完毕,那么首先会执行信号处理函数

int sigsuspend(const sigset_t *mask); //将信号屏蔽码设置为mask,然后等待信号的发生并且执行信号处理函数,sigpending函数可以保证改变进程的屏蔽码和将进程挂起是原子操作。

版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux&C ——信号以及信号处理的更多相关文章

  1. Linux&C ——信号以及信号处理

    linux信号的简单介绍 信号的捕捉和处理 信号处理函数的返回 信号的发送 信号的屏蔽 一:linux信号的简单介绍. 信号提供给我们一种异步处理事件的方法,由于进程之间彼此的地址空间是独立的,所以进 ...

  2. Linux进程间通信——信号集函数

    一.什么是信号 用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中 ...

  3. 详解linux进程间通信-信号

    前言:之前说看<C++ Primer >暂时搁浅一下,迷上公司大神写的代码,想要明白,主要是socket.进程间通信! 知道进程间通信:信号.信号量.管道.消息队列.共享内存(共享存储), ...

  4. Linux线程编程之信号处理

    前言 Linux多线程环境中的信号处理不同于进程的信号处理.一方面线程间信号处理函数的共享性使得信号处理更为复杂,另一方面普通异步信号又可转换为同步方式来简化处理. 本文首先介绍信号处理在进程中和线程 ...

  5. linux 异步信号的同步处理方式

    关于代码的可重入性,设计开发人员一般只考虑到线程安全,异步信号处理函数的安全却往往被忽略.本文首先介绍如何编写安全的异步信号处理函数:然后举例说明在多线程应用中如何构建模型让异步信号在指定的线程中以同 ...

  6. Linux 的信号和线程

    什么是线程 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成,每一个程序都至少 ...

  7. linux kill信号列表

    linux kill信号列表 $ kill -l1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL5) SIGTRAP      6) ...

  8. linux 自定义信号

    从来没试过linux自定义信号,查了下,说是系统只提供了SIGUSR1和SIGUSR2两个,就两个够吗?更要命的是如果要自定义信号如#define SIG_MYSIG   ....的话要改内核才行,哥 ...

  9. Linux之信号

    产生信号五种方法: 按键产生:ctrl+c.ctrl+z.ctrl+\ 系统调用产生:如kill.raise.baort 软件条件产生:如定时器alarm 硬件异常产生:非法访问内存(段错误).除0( ...

随机推荐

  1. Docker系列(18)- 具名挂载和匿名挂载

    容器数据卷挂载方式 容器的数据卷可以看成就是容器的挂载方式:一个宿主机有多个容器,多个容器挂载方式不同,因此宿主机就有多个卷 每一个挂载方式在宿主机上都有一个名称,即卷名 宿主机如何查看这些卷,对使用 ...

  2. 华为云计算IE面试笔记-FusionCompute上的虚拟机A和虚拟机B不能正常通信,请描述可能的故障点和排除方法(分析虚拟机A和虚拟机B不通)

    *快速定位故障点:(考到) ARP:同一二层内可以通过ARP -a命令查询到要访问的主机IP(ARP表项中记录了同一二层中的IP和MAC的对应关系),若查询不到,说明二层出现问题(Vlan 间不通)或 ...

  3. PC+PLC通过Modbus协议构建工控系统

    一. 概述 工业设备采用HMI+PLC控制是比较常见的方案,随着工业自动化的要求越来越高,现在很多设备都要求接入企业MES系统,MES系统一般为WEB系统,接口形式大部分为HTTP协议,这种传统方案和 ...

  4. 使用Jmeter做接口测试(学生信息的6个接口)

    使用Jmeter做接口测试,案例中涉及到接口有:获取学生信息.登录.添加学生信息.学生金币充值.获取所有学生信息.文件上传. 一.获取学生信息(get请求) 服务器名称或IP:输入被请求服务器的名称或 ...

  5. Jmeter压测学习1—第一个项目:登录

    我用的是我们公司的测试环境练习的 网址:http://****:9000/login.html  账号是admin 密码:123456 一.打开Jmeter 找到安装目录:bin->Jmeter ...

  6. 在windoes server2008部署kettle遇到的问题

    本机电脑是windows10,在部署ketle时一切顺利,但在windows server2008服务器上部署,各种报错,毕竟线上环境比较复杂-- 问题一:启动kettle的spoon.bat文件时, ...

  7. vue-混入( mixin 更方便的组件功能复用方法)的使用

    前言 vue 中组件完成了样式和功能的综合复用,通过自定义指令完成了一部分功能的复用,本文总结一下混入在vue项目开发中提供的非常便利的功能复用. 正文 1.混入的分类 (1)全局混入 <div ...

  8. Python代码阅读(第11篇):展开嵌套列表

    Python 代码阅读合集介绍:为什么不推荐Python初学者直接看项目源码 本篇阅读的代码实现了展开嵌套列表的功能,将一个嵌套的list展开成一个一维list(不改变原有列表的顺序). 本篇阅读的代 ...

  9. 7.JVM调优-方法区,堆,栈调优详解

    通常我们都知道在堆空间新生代Eden区满了,会触发minor GC, 在老年代满了会触发full GC, 触发full GC会导致Stop The World, 那你们知道还有一个区域满了一会触发Fu ...

  10. canvas 实现简单的画板功能添加手机端效果 1.01

    在上次的基础上,加了一些代码,手机端可操作 访问网址:https://chandler712.github.io/Item/ <!-- 简单版画板 --> <!DOCTYPE htm ...