Linux进程间通信(三) - 信号
什么是信号
软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。信号机制除了基本通知功能外,还可以传递附加信息。
收到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:
Ø 类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。
Ø 忽略某个信号(SIG_IGN),对该信号不做任何处理,就象未发生过一样。
Ø 对该信号的处理保留系统的默认值(SIG_DFL),这种缺省操作,对大部分的信号的缺省操作是使得进程终止。进程通过系统调用signal来指定进程对某个信号的处理行为。
查看目前支持的信号值
[root@bogon demo]# 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
信号的分类
可以从两个不同的分类角度对信号进行分类:
Ø 可靠性方面:可靠信号与不可靠信号;
Ø 与时间的关系上:实时信号与非实时信号。
可靠信号与不可靠信号
Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,信号值小于SIGRTMIN的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是信号可能丢失。
随着时间的发展,实践证明了有必要对信号的原始机制加以改进和扩充。由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为可靠信号,这些信号支持排队,不会丢失。
信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。Linux在支持新版本的信号安装函数sigation()以及信号发送函数sigqueue()的同时,仍然支持早期的signal()信号安装函数,支持信号发送函数kill()。
信号的可靠与不可靠只与信号值有关,与信号的发送及安装函数无关。目前linux中的signal()是通过sigation()函数实现的,因此,即使通过signal()安装的信号,在信号处理函数的结尾也不必再调用一次信号安装函数。同时,由signal()安装的实时信号支持排队,同样不会丢失。
对于目前linux的两个信号安装函数:signal()及sigaction()来说,它们都不能把SIGRTMIN以前的信号变成可靠信号(都不支持排队,仍有可能丢失,仍然是不可靠信号),而且对SIGRTMIN以后的信号都支持排队。这两个函数的最大区别在于,经过sigaction安装的信号都能传递信息给信号处理函数,而经过signal安装的信号不能向信号处理函数传递信息。对于信号发送函数来说也是一样的。
实时信号与非实时信号
早期Unix系统只定义了32种信号,前32种信号已经有了预定义值,每个信号有了确定的用途及含义,并且每种信号都有各自的缺省动作。如按键盘的CTRL ^C时,会产生SIGINT信号,对该信号的默认反应就是进程终止。后32个信号表示实时信号,等同于前面阐述的可靠信号。这保证了发送的多个实时信号都被接收。
非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。
信号相关函数说明
#include <signal.h>
void (*signal(int signum, void (*handler))(int)))(int);
如果该函数原型不容易理解的话,可以参考下面的分解方式来理解:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler));
第一个参数指定信号的值,第二个参数指定针对前面信号值的处理,可以忽略该信号(参数设为SIG_IGN);可以采用系统默认方式处理信号(参数设为SIG_DFL);也可以自己实现处理方式(参数指定一个函数地址)。
如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR。
传递给信号处理例程的整数参数是信号值,这样可以使得一个信号处理例程处理多个信号。
信号案例说明
案例设计
Ø 进程收到SIGHUP,SIGINT,SIGQUIT,提示收到对应的信号,不做任何处理
Ø 进程中有个计数器,当用户发出SIGUSR1,SIGUSR2时,打印出这个计数器的值
Ø 对信号9(SIGKILL)和信号11(SIGSEGV)分别做忽略和默认处理
代码说明:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <signal.h> int count = ;
void deal_sig(int signum)
{
switch(signum)
{
case : // SIGHUP
printf("signal SIGHUP cached\n");
break;
case : // SIGINT
printf("signal SIGINT cached\n");
break;
case : // SIGQUIT
printf("signal SIGQUIT cached\n");
break;
case : // SIGUSR1
printf("signal SIGUSR1 cached, count = %d\n", count);
break;
case : // SIGUSR2
printf("signal SIGUSR2 cached, count = %d\n", count);
break;
}
return;
} int main(int argc, char** argv)
{
signal(SIGHUP, deal_sig);
signal(SIGINT, deal_sig);
signal(SIGQUIT, deal_sig);
signal(SIGUSR1, deal_sig);
signal(SIGUSR2, deal_sig);
signal(SIGKILL, SIG_IGN);
signal(SIGSEGV, SIG_DFL);
while()
{
count++;
sleep();
}
return ;
}
结果说明:
tty1:
[root@bogon ipc]# g++ -g -o ipc_signal ipc_signal.cpp
[root@bogon ipc]# ./ipc_signal
^Csignal SIGINT cached // 这里按下 CTRL + C
signal SIGHUP cached
signal SIGINT cached
signal SIGQUIT cached
signal SIGUSR1 cached, count = 73
signal SIGUSR2 cached, count = 79
Killed // 这里发现SIGKILL信号是忽略不掉的,进程还是退出了
[root@bogon ipc]# ./ipc_signal
Segmentation fault (core dumped) // 收到段错误信号,产生core并退出
tty2:
[root@bogon ipc]# ps axu|grep ipc_signal
root 20380 0.0 0.0 11740 828 pts/1 S+ 00:50 0:00 ./ipc_signal
root 20389 0.0 0.0 103252 812 pts/2 S+ 00:50 0:00 grep ipc_signal
[root@bogon ipc]# kill -HUP 20380
[root@bogon ipc]# kill -INT 20380
[root@bogon ipc]# kill -QUIT 20380
[root@bogon ipc]# kill -USR1 20380
[root@bogon ipc]# kill -USR2 20380
[root@bogon ipc]# kill -KILL 20380
[root@bogon ipc]# ps axu|grep ipc_signal
root 20445 0.0 0.0 11736 780 pts/1 S+ 00:52 0:00 ./ipc_signal
root 20448 0.0 0.0 103252 812 pts/2 S+ 00:53 0:00 grep ipc_signal
[root@bogon ipc]# kill -SEGV 20445
Linux进程间通信(三) - 信号的更多相关文章
- [转]Linux进程间通信——使用信号
转载于:http://blog.csdn.net/ljianhui/article/details/10128731 经典!!! Linux进程间通信——使用信号 一.什么是信号 用过 ...
- Linux进程间通信——使用信号
一.什么是信号 用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中 ...
- 练习--LINUX进程间通信之信号SIGNAL
同样的,信号也不要太迷信可靠信号及不及靠信号,实时或非实时信号. 但必须要了解这些信号之间的差异,函数升级及参数,才能熟练运用. ~~~~~~~~~~~~~~~~ 信号本质 信号是在软件层次上对中断机 ...
- Linux进程间通信方式--信号,管道,消息队列,信号量,共享内存
1.概述 通信方法 无法介于内核态与用户态的原因 管道(不包括命名管道) 局限于父子进程间的通信. 消息队列 在硬.软中断中无法无阻塞地接收数据. 信号量 无法介于内核态和用户态使用. 内存共享 需要 ...
- linux进程间通信之信号
1.wait()函数 原型:pid_t wait(int *status) 子进程退出时,它向父进程发送一个SIGCHLD信号,默认情况是总是忽略SIGCHLD信号,此时进程状态一直保留在内存中,因 ...
- Linux进程间通信——使用信号量
这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...
- Linux进程间通信--使用信号量【转】
本文转载自:http://blog.csdn.net/ljianhui/article/details/10243617 这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号 ...
- Linux进程间通信——使用信号量(转)
这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...
- Linux进程间通信——使用信号量【转】
本文转载自:http://blog.csdn.net/ljianhui/article/details/10243617 这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号 ...
随机推荐
- ElasticSearch 专业术语
1.Analysis(分析) 分析的过程就是将全文(full text)转换成 术语/分词(terms). 这取决于使用那个分析器,这些短语:“FOO BAR”, “Foo-Bar”, “foo,ba ...
- 【Hadoop】Hadoop MR 自定义分组 Partition机制
1.概念 2.Hadoop默认分组机制--所有的Key分到一个组,一个Reduce任务处理 3.代码示例 FlowBean package com.ares.hadoop.mr.flowgroup; ...
- jquery给多个span赋值
因为我想在页面载入完毕后,有几个地方显示当前时间,所以我须要给多个span赋值. span代码的写法例如以下: <span name="currentDate">< ...
- Node.js 网页爬虫再进阶,cheerio助力
任务还是读取博文标题. 读取app2.js // 内置http模块,提供了http服务器和客户端功能 var http=require("http"); // cheerio模块, ...
- 使用theHarvester 进行邮箱和子域名的收集
下载地址:https://github.com/laramies/theHarvester 先要安装python的 reqeusts 库 安装pip install reqeustsmail -d b ...
- php 位运算符的实际应用(权限判断)
关键代码: define("READ", 1); define("WRITE", 2); define("DELETE", 4); defi ...
- 字符串截取 及 substr 和 substring 的区别
1..字符串截取 str.substr(0, 1) // 获取字符串第一个字符 str.substr(-1) // 获取字符串最后一个字符 str.charAt(str.length - 1) // ...
- 【SpringMVC学习11】SpringMVC中的拦截器
Springmvc的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理.本文主要总结一下springmvc中拦截器是如何定义的,以及测试拦截器的执行情况和使用 ...
- nightwatchjs --Expect element to not include text
to have NightWatch to find text in a div. browser.assert.containsText('#output', 'find me') But how ...
- C/C++中字符串与数字之间的转换
主要有两种方式:C 中能够使用 sprintf 将数字转为字符数组,sscanf 将字符数组转为数字:而在 C++ 中不仅能够使用 C 中的方法,还能够使用 stringstream 实现字符串与数字 ...