Linux下信号

信号和 中断是很类似的,只不过是一个是硬件中断,另外一个是软中断。中断是系统对于异步事件的响应。

简单理解就是:中断源 发出 中断信号 在 中断向量表 中执行 中断处理程序 之前保存 现场信息

异步事件的响应:进程执行代码的过程中可以随时被打断,然后去执行异常处理程序。

中断源发出中断信号,CPU判断中断是否屏蔽屏蔽、保护现场 ,cpu执行中断处理程序, cpu恢复现场,继续原来的任务。

中断向量表保存了中断处理程序的入口地址。

中断个数固定,操作系统启动时初始化中断向量表。

中断有优先级,中断可以屏蔽。

中断分类

硬件中断(外部中断)

外部中断是指由外部设备通过硬件请求的方式产生的中断,也称为硬件中断, 例如DMA中断

软件中断(内部中断)

内部中断是由CPU运行程序错误或执行内部程序调用引起的一种中断,也称为软件中断。

x86平台INT指令 ARM软中断指令SWI

信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。

信号是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等

信号是在软件层次上对中断的一种模拟,所以通常把它称为是软中断

信号和中断的区别

信号与中断的相似点:

(1)采用了相同的异步通信方式;

(2)当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;

(3)都在处理完毕后返回到原来的断点;

(4)对信号或中断都可进行屏蔽。

信号与中断的区别:

(1)中断有优先级,而信号没有优先级,所有的信号都是平等的;

(2)信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;

(3)中断响应是及时的,而信号响应通常都有较大的时间延迟。

进程对信号的三种相应

忽略信号

不采取任何操作、有两个信号不能被忽略:SIGKILL(9号信号)和SIGSTOP。

进程不能忽略SIGKILL、SIGSTOP这两个信号。如果应用程序可以忽略这2个信号,系统管理无法杀死、暂停进程,无法对系统进行管理。。SIGKILL(9号信号)和SIGSTOP信号是不能被捕获的。

捕获并处理信号

内核中断正在执行的代码,转去执行先前注册过的处理程序。

执行默认操作

默认操作通常是终止进程,这取决于被发送的信号。

signal信号安装函数 就是对PCB中的信号状态进行重置

typedef void (*__sighandler_t) (int);

#define SIG_ERR ((__sighandler_t) -1)

#define SIG_DFL ((__sighandler_t) 0)

#define SIG_IGN ((__sighandler_t) 1)

__sighandler_t signal(int signum, __sighandler_t handler);

signal是一个带signum和handler两个参数的函数,准备捕捉或屏蔽的信号由参数signum给出,接收到指定信号时将要调用的函数由handler给出

handler这个函数必须有一个int类型的参数(即接收到的信号代码),它本身的类型是void

handler也可以是下面两个特殊值:

SIG_IGN     屏蔽该信号

SIG_DFL     恢复默认行为

其实就是上面定义的两个宏而已,也就是0 和 1.

不可靠信号和可靠信号

linux信号机制基本上是从unix系统中继承过来的。早期unix系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,它的主要问题是:

进程每次处理信号后,就将对信号的响应设置为默认动作。在某些情况下,将导致对信号的错误处理;因此,用户如果不希望这样的操作,那么就要在信号处理函数结尾再一次调用signal(),重新安装该信号。

早期unix下的不可靠信号主要指的是进程可能对信号做出错误的反应以及信号可能丢失。

linux支持不可靠信号,但是对不可靠信号机制做了改进:在调用完信号处理函数后,不必重新调用该信号的安装函数(信号安装函数是在可靠机制上的实现)。因此,linux下的不可靠信号问题主要指的是信号可能丢失。

unix信号机制不可靠地方,1)处理完信号以后,需要重新再注册信号;2)信号可能丢失。linux下已经对1做了优化。Linux下主要是指信号丢失,比如 发送了3个信号,可能只能接受一个信号。

可靠信号,这些信号支持排队,不会丢失。同 时,信号的发送和安装也出现了新版本:信号发送函数sigqueue()及信号安装函数sigaction()。

不可靠信号不支持排队,可靠信号支持排队。

信号注册函数 和 信号发送函数

signal  sigaciton 信号安装函数 都是调用内核服务do_signal函数,应用系统无法直接调用的函数

Int kill(pid_t pid, int siq)

Int kill(pid_t pid, int siq)

参数组合情况解释:

kill(pid_t pid, int siq)

pid>0 将信号sig发给pid进程

pid=0 将信号sig发给同组进程

pid=-1 将信号sig发送给所有进程,调用者进程有权限发送的每一个进程(除了1号进程之外,还有它自身)

pid<-1 将信号sig发送给进程组是pid(绝对值)的每一个进程

如果在fork之前安装信号,则子进程可以继承信号。

sleep函数几点说明

1)sleep函数作用,让进程睡眠。

2)能被信号打断,然后处理信号函数以后,就不再睡眠了。直接向下执行代码

3)sleep函数的返回值,是剩余的秒数

因此 如果想要休眠足够的秒数,需要使用do while循环来进行。

raise  给自己发送信号。raise(sig)等价于kill(getpid(), sig);

killpg  给进程组发送信号。killpg(pgrp, sig)等价于kill(-pgrp, sig);

sigqueue 给进程发送信号,支持排队,可以附带信息。

因此可以给进程发送信号的函数有,kill, killgp, raise, sigqueue。

pause()函数

将进程置为可中断睡眠状态。然后它调用内核函数schedule(),使linux进程调度器找到另一个进程来运行。pause使调用者进程挂起,直到一个信号被捕获。

alarm函数,设置一个闹钟延迟发送信号。告诉linux内核n秒中以后,发送SIGALRM信号;

可重入函数和不可重入函数

为了增强程序的稳定性,在信号处理函数中应使用可重入函数。

所谓可重入函数是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会出错。因为进程在收到信号后,就将跳转到信号处理函数去接着执行。如果信号处理函数中使用了不可重入函数,那么信号处理函数可能会修改原来进程中不应该被修改的数据,这样进程从信号处理函数中返回接着执行时,可能会出现不可预料的后果。不可再入函数在信号处理函数中被视为不安全函数。满足下列条件的函数多数是不可再入的:(1)使用静态的数据结构,如getlogin(),gmtime(),getgrgid(),getgrnam(),getpwuid()以及getpwnam()等等;(2)函数实现时,调用了malloc()或者free()函数;(3)实现时使用了标准I/O函数的。使用man 7 signal 查找可重入函数和不可重入函数。

信号的阻塞和未达

信号在内核中的表示

执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。注意,阻塞和忽略是不同,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。递达的信号被忽略了,同样是不能执行回调函数的。

PCB进程控制块中函数有信号屏蔽状态字(block)信号未决状态字(pending)还有是否忽略标志;信号屏蔽状态字(block),1代表阻塞、0代表不阻塞;信号未决状态字(pending)的1代表未决,0代表信号可以抵达了;向进程发送SIGINT,内核首先判断信号屏蔽状态字是否阻塞,信号未决状态字(pending相应位制成1;若阻塞解除,信号未决状态字(pending)相应位制成0;表示信号可以抵达了。block状态字、pending状态字 64bit;block状态字用户可以读写,pending状态字用户只能读;这是信号设计机制。是通过block间接的控制pending状态字,使它们保持一直状态。

信号集操作函数

#include <signal.h>

int sigemptyset(sigset_t *set);  把信号集情况64bit/8=8个字节的buffer

int sigfillset(sigset_t *set); 把信号集情况1

int sigaddset(sigset_t *set, int signo); 根据signo,把信号集中的对应为置成1

int sigdelset(sigset_t *set, int signo); 根据signo,把信号集中的对应为置成0

int sigismember(const sigset_t *set, int signo);//判断signo是否在信号集中

上面的仅仅是操作了信号集合,还没有将相应的信号集放置到内核中去,需要使用下面这个函数来操作对应的信号屏蔽字。

读取或更改进程的信号屏蔽状态字(block)

#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

功能:读取或更改进程的信号屏蔽字。

返回值:若成功则为0,若出错则为-1

如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,

通过sigprocmask可以将对应信号字类型中的数据写到进程的block状态字中。

sigpending用于获取信号未决状态字(pending)信息

函数原型是这样的。int sigpending(sigset_t *set);

到此为止,已经完成了信号的设置工作,剩下的 就是信号的发送 和信号的处理工作。

原文地址:https://www.cnblogs.com/randyniu/p/9124982.html

时间: 2024-08-04 04:25:03

Linux下信号的相关文章

Linux 下信号理解(一)

Linux提供了信号传递进程消息的机制,什么是信号?它是一种非常短的消息,短到只有一个数字.值得强调的是信号和信号量只少了一个字,但他们完全是不同的概念,信号量仅用于同步代码段,而信号则用于传递消息. 一 .信号的编号:通过kill -l 命令可以看到 二.信号机制 可以通过man 7 signal 三.几种默认处理信号的方式: Term表示终止当前进程. Core表示终止当前进程并且Core Dump 生成core文件用于调试(Core Dump 用于gdb调试). Ign表示忽略该信号. S

Linux下信号的简单使用

1,1个main, 包含2个while, 不要被两个while中的sleep所迷惑,这里只有main()这一个主线程(进程)在运行,程序会按照自上而下顺序执行. 遇到第1个while循环中的sleep时,本线程暂停执行,交给其它线程处理,但是因为该进程只有一个线程,所以只有静静的sleep到指定时间(1s)后,再继续暂停点处的循环, 但因为第1个while循环的条件仍然成立,所以执行的仍然是第1个while循环体. 我原来想的结果是i=1,会和i=1000交叉着打印,其实这种想法是错误的. 该程

Linux下信号种类以及特殊信号的含义

可看到Linux支持的信号列表: $ kill -l1) SIGHUP        2) SIGINT        3) SIGQUIT       4) SIGILL 5) SIGTRAP       6) SIGABRT       7) SIGBUS        8) SIGFPE 9) SIGKILL      10) SIGUSR1      11) SIGSEGV      12) SIGUSR213) SIGPIPE      14) SIGALRM      15) SIG

转 linux 之信号

APUE讲信号真是生涩,着实读者无趣,如是找一篇总结比较好的博客. 原文http://blog.chinaunix.net/uid-24774106-id-4061386.html Linux编程,信号是一个让人爱恨交加又不得不提的一个领域.最近我集中学习了Linux的signal相关的内容,分享出来,也为防止自己忘记.     信号的本质是异步.异步一这个词,听着高端大气上档次,又让人云山雾绕,其则不然.其实我们想想,我们这个世界是异步的,每个人干事儿,并不总是 A->B->C->D这

linux下的常见信号总结

在linux下有很多信号,按可靠性分为可靠信号和非可靠信号,按时间分为实时信号和非实时信号,linux进程也有三种方式来处理收到的信号: (1)忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL及SIGSTOP: (2)捕捉信号.定义信号处理函数,当信号发生时,执行相应的处理函数: (3)执行缺省操作,Linux对每种信号都规定了默认操作. Linux进程对实时信号的缺省反应是进程终止.但是对于高性能服务器编程来说,这是致命的缺陷,对于这类服务器需要保证在收到各种信号后仍然

linux下 signal信号机制的透彻分析与各种实例讲解

转自:http://blog.sina.com.cn/s/blog_636a55070101vs2d.html 转自:http://blog.csdn.net/tiany524/article/details/17048069 首先感谢上述两位博主的详细讲解. 虽然内容有点长,但是分析的很全面,各种实例应用基本都考虑到了. 本文将从以下几个方面来阐述信号: (1)信号的基本知识 (2)信号生命周期与处理过程分析 (3) 基本的信号处理函数 (4) 保护临界区不被中断 (5) 信号的继承与执行 (

Linux:信号下

在Linux:信号上博文中我们写了一个mysleep,但是实际上这个函数在多线程环境下是会出现错误的,也就是我们这个mysleep函数并不是可重入函数, 现在重新审视"mysleep"程序,设想这样的时序: 1. 注册SIGALRM信号的处理函数. 2. 调用alarm(nsecs)设定闹钟. 3. 内核调度优先级更高的进程取代当前进程执行,并且优先级更高的进程有很多个,每个都要执行很长时间 4. nsecs秒钟之后闹钟超时了,内核发送SIGALRM信号给这个进程,处于未决状态. 5.

[转] linux下的僵尸进程处理SIGCHLD信号

什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些 信息至少包括进程ID,进程的终止状态,以及该进程使用的CPU时间,所以当终止子进程的父进程调用wait或waitpid时就可以得到这些信息. 而僵尸进程就是指:一个进程执行了exit系统调用退出,而其父进程并没有为它收尸(调用wait或waitpid来获得它的结束状态)的进程. 任何一个子进程(init除外)在exit后并非马上就消失,而是

linux下的僵尸进程处理SIGCHLD信号

什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些信息至少包括进程ID,进程的终止状态,以及该进程使用的CPU时间,所以当终止子进程的父进程调用wait或waitpid时就可以得到这些信息. 而僵尸进程就是指:一个进程执行了exit系统调用退出,而其父进程并没有为它收尸(调用wait或waitpid来获得它的结束状态)的进程. 任何一个子进程(init除外)在exit后并非马上就消失,而是留