进程间通信--信号
来源:互联网 发布:落樱神斧华盛顿知乎 编辑:程序博客网 时间:2024/04/30 04:48
什么是信号
用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中的进程捕获到这个信号然后作出一定的操作并最终被终止。
信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些行动。通常信号是由一个错误产生的。但它们还可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程。一个信号的产生叫生成,接收到一个信号叫捕获。
怎么处理信号
第一种是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。
第二种方法是,忽略某个信号,对该信号不做任何处理,就象未发生过一样。
第三种方法是,对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信号的缺省操作是使得进程终止。进程通过系统调用signal来指定进程对某个信号的处理行为。
如何指定信号处理函数
1、信号安装
(1)、signal()
#include void (*signal(int signum, void (*handler))(int)))(int);
参数指定针对前面信号值的处理,可以忽略该信号(参数设为SIG_IGN);可以采用系统默认方式处理信号(参数设为SIG_DFL);也可以自己实现处理方式(参数指定一个函数地址)。
如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR。
(2)、sigaction()
#include int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
sigaction
函数用于改变进程接收到特定信号后的行为。该函数的第一个参数为信号的值,可以为除SIGKILL
及SIGSTOP
外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction
的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理;第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性。
下面是signal()的例子,最好在终端跑而不是xcode之类的编译器,我在编译器上跑一直没成功过
#include <stdio.h>#include <signal.h>#include <unistd.h>void signal_handler(int sig){ printf("\nINT signal received~~~ %d\n", sig); (void)signal(SIGINT, SIG_DFL);}int main(){ if(signal(SIGINT,signal_handler) ==SIG_ERR) return 0; while (1) {// raise(SIGINT); printf("\nHello Fantasy\n"); sleep(1); } return 0;}
当然想要有更好的健壮性也可以使用sigaction()
这个方法
void signal_handler(int sig){ printf("\nINT signal received~~~ %d\n", sig); (void)signal(SIGINT, SIG_DFL);}int main(){ struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); //使sigaction函数重置为默认行为 act.sa_flags = SA_RESETHAND; sigaction(SIGINT, &act, 0); while (1) { // raise(SIGINT); printf("\nHello Fantasy\n"); sleep(1); } return 0;}
其中 act.sa_flags
可疑有一下选项
接受端的信号处理注册部分弄完了,那么如何向相应进程发送消息呢
发送信号
–KILL
先来看看kill函数,进程可以通过kill函数向包括它本身在内的其他进程发送一个信号,如果程序没有发送这个信号的权限,对kill函数的调用就将失败,而失败的常见原因是目标进程由另一个用户所拥有。想一想也是容易明白的,你总不能控制别人的程序吧,当然超级用户root,这种上帝般的存在就除外了。
#include <sys/types.h>#include <signal.h>int kill(pid_t pid, int sig);
kill调用失败返回-1,调用失败通常有三大原因:
1、给定的信号无效(errno = EINVAL)
2、发送权限不够( errno = EPERM )
3、目标进程不存在( errno = ESRCH )
– alarm
#include <unistd.h>unsigned int alarm(unsigned int seconds);
它的作用是在一段时间之后定时发送一个信号。
像这样~~~
#include <unistd.h>#include <sys/types.h>#include <stdlib.h>#include <stdio.h>#include <signal.h>static int child_flag = 0;void signal_handler(int sig){ child_flag = 1;}int main(){ pid_t pid; pid = fork(); switch(pid) { case -1: perror("fork failed\n"); exit(EXIT_FAILURE); case 0: //子进程 sleep(2); //向父进程发送信号 kill(getppid(), SIGALRM); exit(0); default:; } //设置处理函数 signal(SIGALRM, signal_handler); while(!child_flag) { printf("Hello Fantasy!\n"); sleep(1); } printf("\nFantasy is released %d\n", SIGALRM); exit(0);}
安全性
我们的程序是要用在多进程环境的,一个程序可能会收到数个程序发来的信号,根据优先级执行相应的处理函数,那么信号处理函数的可重入性就显得至关重要,不能调用不可重入的函数
以下是一些可重入的函数:
Thats all~~~
- 进程间通信--信号
- Linux进程通信-信号
- 进程间通信-信号
- 进程间通信--信号
- 进程间通信--信号
- 进程间通信-信号
- 进程间通信---信号
- 【进程间通信】信号
- 进程间通信----信号
- 【进程间通信】信号
- 信号通信(进程间通信)
- 进程间通信之信号
- 进程间通信:信号机制
- 3、进程间通信-信号
- 进程间通信--信号发送
- 父子进程间信号通信
- Linux 进程间通信 信号
- 嵌入式 进程间通信--信号
- jquery
- Nova Suspend/Rescue 操作详解 - 每天5分钟玩转 OpenStack(35)
- basic file operations
- 2013蓝桥决赛C/C++B组
- java大杂烩
- 进程间通信--信号
- 数据库的原理
- 获取远程redis服务器上的值
- 从零开始配置redis主从同步
- Zepto.js
- 单一职责原则
- python *args,**kwargs使用
- 第12周项目1:实现复数类中的运算符重载(2)
- 多周期CPU设计