信号原理
- 信号机制:事件促使内核向进程发送信号
- 事件类型:
- 键盘按键请求内核产生信号:ctrl+c、ctrl+/等
- 进程执行出错时,如越界访问,0做除数,整形溢出。内核给进程发信号
- 一个进程调用kill给另一个进程发信号。
- 信号机制过程
信号未决(信号处理之前的状态):事件产生->内核发送信号给指定进程->信号注册(信号进PCB)
信号递送(信号处理动作):信号被屏蔽/若未被屏蔽,信号从PCB注销->信号处理 - 信号处理方式
- 按默认方式处理:man 7 signal可以查看每个信号的默认处理方式
- 忽略信号,SIGKILL和SIGSTOP不能被忽略
- 捕捉信号,作出反应
- 可用于进程间使用信号通信
- 异步通信机制(约定信号处理机制)
-
shell中用 kill -l 查看信号
- 信号分类
- 小于32号为不可靠信号,不支持信号队列。后面为可靠信号,支持信号队列
- 同步信号:本进程操作产生的信号。异步信号:进程之外的事件引发的信号。
- 信号的意义见官方信号表
http://man7.org/linux/man-pages/man7/signal.7.html
也可在终端输入man 7 signal
查看信号详细信息和默认处理方式
信号处理函数API
include <signal.h>
__sighandler_t signal(int signum,__sighandler_t handler)
参数表:
signum:要处理的信号
handler:信号处理函数
- __sighandler_t的定义:typedef void (*__sighandler_t)(int);
函数指针:返回值为void,有一个类型为int的参数
此参数对应三种不同的应对- SIG_IGN:忽略
- SIG_DFL:默认
- 函数名:用户自己定义的反应函数
返回值:
不为-1:成功
SIG_ERR:出错
示例代码:
#include <signal.h>
#include <stdlib.h>//perror,exit()
#include <unistd.h>//fork(),pause()
#include <sys/wait.h>//wait()
#include <iostream>
using namespace std;
void fun(int signal)
{
cout << "process:"<<getpid()<<"have captured the signal " << endl;
}
int main()
{
int pid;
if( ( pid = fork() ) == -1 )
{
perror("fork");
exit(1);
}
else if(pid == 0)//son process
{
signal(SIGINT,fun);
//SIGINT:signal from keyboard
//约定信号处理函数
cout << "waiting for signal" << endl;
pause();//挂起等待信号
}
else//parent process
{
sleep(1);
kill(pid,SIGINT);//发送信号
wait(NULL);
}
}
也可发送信号10(用户自定义信号)来进行进程通信
signal函数存在的问题
- 信号处理不可靠
处理结束后需要再次设置监听,所以常用此结构
这种结构在相应处理完信号到重设监听状态有一段危险时间(虽然很短)void handler(int signo) { signal(SIGINT,handler); ... }
- 不方便获取当前信号处理方式
- 无法处理多个信号--无法阻塞信号
其他信号相关api(待更新)
- sigaction:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
- 当act为空,oldact非空:获取signum当前的处理方式
- 当act非空,oldact为空:安装信号处理函数
- sigaction结构体
struct sigaction {
void (*sa_handler)(int);//信号处理函数句柄,不带参数
void (*sa_sigaction)(int, siginfo_t *, void *);//信号处理函数句柄,带参数
sigset_t sa_mask;//响应信号:哪些信号可以阻塞等待执行
int sa_flags;//设置是否在信号响应后恢复对信号的默认处理
void (*sa_restorer)(void);
}
一个小例子
通过argv来传送pid和signum
发送端
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
void main(int argc,char**argv)
{
pid_t pid;
pid=(pid_t)atoi(argv[1]);
int signum;
signum = atoi(argv[2]);
union sigval mysigval;
if(kill(pid,signum)==-1)
printf("send error\n");
sleep(2);
}
接收端
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>//atoi
void new_op(int signum)
{
printf("recieve signumm %d\n",signum);
}
int main(int argc,char**argv)
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_handler=new_op;
act.sa_flags=SA_RESETHAND;
if(sigaction(30,&act,NULL)<0)
{
printf("install sigal error\n");
}
pid_t pid;
pid=getpid();
printf("pid : %d\n",pid);
sleep(10);
}
- kill:发送信号
- raise:给自己发信号
- alarm:计时器
- pause:挂起(等信号)(pause+alarm = sleep):
- sigqueue:可以在发信号的时候传参