博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux(进程间通信-信号)
阅读量:7022 次
发布时间:2019-06-28

本文共 3445 字,大约阅读时间需要 11 分钟。

hot3.png

信号通信是在软件层面上对中断机制的一种模拟。信号是进程间通信机制中唯一的异步通信机制。

信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。它可以在任何时候发给某一进程,而无需知道该进程的状态。如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它为止。

信号事件的产生有硬件来源(如按下键盘或者其他硬件故障)和软件来源,软件来源除了软件调用,还包括一些非法运算等操作。

进程可以通过3种方式来响应一个信号:

1、忽略信号:即对信号不做任何处理,其中,有两个信号不能忽略,SIGKILL & SIGSTOP。

2、捕捉信号:定义信号处理函数,当信号发生时,执行相应的操作。

3、执行默认操作:Linux对每种信号都规定了默认操作,下表包含了部分的定义:

信号的相关函数包括信号的发送和设置,具体如下:

发送信号的函数:kill()    raise()    sigqueue()

设置信号的函数:signal()    sigaction()    setitimer()

其他函数:alarm()    pause()

信号发送:kill()    raise()

kill() 函数同kill 系统命令一样,可以发送信号给进程或是进程组(实际上,kill 系统命令就是调用 kill() 函数。需要注意的是,它不仅可以终止进程(发送 SIGTERM信号),也可以向进程发送其他信号。

注意:raise() 函数只能向进程自身发送信号

函数原型:

int kill(pid_t pid,int sig);

int raise(int sig);

说明:pid 为进程号;sig 为信号类型号

raise() 例程:进程在执行while(1)循环输出字符串的时候调用raise(SIGSTOP)使进程停止 \

/* raise.c */#include 
#include
#include
#include
int main(){ printf("PID: %d\n",getpid()); while(1){ printf("run\n"); raise(SIGSTOP); }}

程序输出:

PID: 55859run[1]+  Stopped                 ./a.out

可以看到,进程在输出了第句run之后调用raise(SIGSTOP)使进程停止了,使用命令 "ps -ef | grep a.out" 可以看到进程并没有消失,确认进程只是暂停。使用 "kill -9 55859" 杀死进程。

kill() 例程:子进程间隔10us打印一串字符,父进程100us后 kill 子进程。

/* kill.c */#include 
#include
#include
#include
#include
int main(){ pid_t pid; pid = fork(); if(pid == -1){ perror("fork failed:"); exit(-1); } if(pid == 0){ while(1){ printf("child\n"); sleep(1); } }else{ sleep(3); kill(pid,SIGINT); sleep(3); exit(0); }}

alarm() 可以在进程中设置一个定时器,当定时器指定的时间到时,它就向进程发送SIGALARM信号。一个进程只能有一个闹钟,重复设置,前面的闹钟会被覆盖。

示例:

#include 
#include
#include
int main(){ alarm(3); while(1){ printf("run\n"); sleep(1); pause(); } printf("waken up\n");}

程序输出:

runAlarm clock

注释掉 pause(); 的程序输出:

runrunrunAlarm clock

信号的设置:signal()    sigaction()

signal() 用于设置信号的处理函数。主要用于前32种非实时信号的处理,不支持信号传递信息。

注:signal() 是UNIX系统的遗留版本,不同的系统表现不一且在有的系统上会出现信号丢失的问题。且在man中亦提到,’应避免使用signal(),使用sigaction()代替‘。所以这里我们就不讨论signal(),直接使用sigaction()。

函数原型:

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

说明:signum - 信号类型,除SIGKILL & SIGSTOP 外的任何一个信号;act - 指向sigaction结构体的指针,包含对特殊信号的处理;oldact - 保留信号原先的处理方式。

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 和 sa_sigaction 两者只能定义一个,且sa_sigaction 是 sa_handler的升级版本,由于sa_sigaction又太复杂,在这里我们就不讨论sa_sigaction。

sa_handler 是一个函数指针,指向信号处理函数。它既可以是用户自定义的处理函数,也可以为SIG_DFL(采用默认的处理方式)或SIG_IGN(忽略信号)。信号处理函数只有一个参数,即信号类型。

sa_mask是一个信号集合,用来指定在信号处理函数执行过程中哪些信号被屏蔽。

sa_flags 中包含了许多标志位,都是和信号处理相关的选项。常见可选值包括(SA_NODEFER/SA_NOMASK/SA_NOCLDSTOP/SA_RESTART/SA_ONESHOT/SA_RESETHAND)

sigaction() 示例:

/* signal.c */#include 
#include
#include
#include
void my_func(int sign_no){ if(sign_no == SIGINT){ printf("I have got SIGINT\n"); }else if(sign_no == SIGQUIT){ printf("I have got SIGQUIT\n"); }}int main(){ struct sigaction action; //初始化结构体 sigaction(SIGINT,0,&action); action.sa_handler = my_func; sigaction(SIGINT,&action,0); sigaction(SIGQUIT,0,&action); action.sa_handler = my_func; sigaction(SIGQUIT,&action,0); printf("Waiting for signal SIGINT & SIGQUIT\n:"); pause(); exit(0);}

 

转载于:https://my.oschina.net/neverdead/blog/751824

你可能感兴趣的文章
广告点击率预测 [离线部分]
查看>>
CodeForces 659F Polycarp and Hay
查看>>
Servlet客户请求的处理:HTTP请求报头HttpServletRequest接口应用
查看>>
http://stormzhang.com/devtools/2014/12/09/android-studio-tutorial3/ 安卓studio 安装教程
查看>>
ES6(5) - 变量的解构赋值
查看>>
vc++6.0 模拟鼠标点击代码 木马程序的编写 VC 模拟键盘输入
查看>>
VC用法汇总
查看>>
ORACLE同义词使用
查看>>
无法将类型“XXX”隐式转换为“XXX[]”(Cannot implicitly convert type 'XXX' to 'XXX[]')
查看>>
react-navigation
查看>>
pat 1014 1017 排队类问题
查看>>
设计循环队列
查看>>
前端UI框架小汇总
查看>>
ecshop 批量生成订单信息
查看>>
Java常用系统变量收集
查看>>
基于Hadoop2.7.3集群数据仓库Hive1.2.2的部署及使用
查看>>
常见负载均衡的优点和缺点对比(Nginx、HAProxy、LVS)
查看>>
Mac电脑C语言开发的入门帖
查看>>
C++ 中 int、 char、 char*、 const char*、 string之间的转换
查看>>
上班两周
查看>>