信号
信号是进程间通信的一种方式 这种方式并没有传输数据 只是在内核中传了一个信号(整数)
信号的表示是一个整数
不同的信号值 代表不同的含义 当然用户可以自定义信号
信号的本质其实是软中断
信号会中断正在进行的程序 转而去处理中断(处理函数)
处理完中断后 再回来继续执行原有的程序
注意:如果用户没有显式地处理信号 系统收到信号默认地处理方式大多是终止进程
查看信号可以在终端上输入
man 7 signal
几个常用的信号:
Signal Value Action Comment
──────────────────────────────────────────────────────────────────────
SIGINT 2 Term Interrupt from keyboard
从键盘上收到了中断信号 按下ctrl+c就会产生这个信号
SIGQUIT 3 Core Quit from keyboard
默认的处理是输出信息然后终止进程 按下ctrl+\就会产生这个信号
SIGFPE 8 Core Floating-point exception
浮点数运算异常的时候 产生SIGFPE信号
SIGKILL 9 Term Kill signal
杀死进程 不可被捕获和忽略
SIGSTOP 17,19,23 Stop Stop process
停止进程 不可被捕获和忽略
SIGSEGV 11 Core Invalid memory reference
非法内存引用时 就会收到SIGSEGV信号
比如段错误 一旦产生段错误 进程收到SIGSEGV信号 此时输出信号
然后终止进程
SIGPIPE 13 Term Broken pipe: write to pipe with no
readers; see pipe(7)
当你往一个管道写数据时 没有读端进程就会产生SIGPIPE信号
SIGALRM 14 Term Timer signal from alarm(2)
定时信号 在进程调用alarm时 会在超时的时候 就会产生SIGALRM信号
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
SIGCHLD 20,17,18 Ign Child stopped or terminated
当子进程停止或终止的时候 父进程就会收到该信号
父进程收到这个信号并不会怎么样 因此信号的默认行为是忽略
linux下信号相关的API函数
1.发送信号kill
NAME
kill - send signal to a process
SYNOPSIS
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
函数功能: kill用来把一个信号发送到一个指定的进程或多个进程
kill不仅仅是一个函数 也是一条指令
头文件:如上
参数列表:
pid : 指定信号的接收者(可能是多个进程 )
pid > 0 pid表示指定的那一个要发送的进程
pid = 0 发送信号给 与调用进程同组的所有进程
pid = -1 发送信号给系统所有进程(有权限发送的所有进程)
pid < -1 发送信号给组id等于pid绝对值的所有进程
sig: 你要发送的信号 参考上面的宏
返回值:
成功(至少有一个进程成功接收到信号)返回0
失败返回-1 并且errno被设置
- raise
NAME
raise - send a signal to the caller
SYNOPSIS
#include <signal.h>
int raise(int sig);
函数功能: 发送一个信号给自己
raise(sig) 《==》 kill( getpid(), sig)
- alarm
NAME
alarm - set an alarm clock for delivery of a signal
SYNOPSIS
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
函数功能: alarm定时发送一个闹钟(SIGALRM)信号给本进程
"闹钟":每个进程都有属于自己的一个“闹钟” “闹钟”时间到了 进程就会收到
一个SIGALRM信号 但是同一时刻只有一个“闹钟”生效
头文件:如上
参数列表:
seconds: 多少秒后 发送一个“闹钟信号”
如果为0 代表取消上一个“闹钟”
返回值:
返回上一个闹钟的剩余秒数
4.捕捉信号 改变信号地处理方式
NAME
signal - ANSI C signal handling
SYNOPSIS
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t是一个函数指针类型 它可以用来定义函数指针变量
这个变量指向一个无返回值 并带有一个int类型参数地函数
sighandler_t signal(int signum, sighandler_t handler);
函数功能: 捕捉对应地信号 使其按照指定地方式去处理
参数列表:
signum: 你要捕捉哪个信号 要捕捉地那个信号地信号值
handler: 信号的处理方式 一般有如下三种:
a.自定义的函数
这个函数为无返回值 但是带一个int的参数(用来保存收到的那个信号的信号值)的函数
大概格式:
void my_signal_handle(int sig)
{
//用户自定义处理
}
b.SIG_IGN 忽略该信号
c.SIG_DFL default 采用操作系统默认的处理方式
返回值:
成功返回信号的上一次的处理方式
失败 返回SIG_ERR 同时errno被设置
5.pause
NAME
pause - wait for signal
SYNOPSIS
#include <unistd.h>
int pause(void);
让进程停在那里 等待某个信号的到来。直到收到信号
返回值:
当一个信号被捕捉 且信号处理函数返回后返回 这种情况下返回-1
实现pause
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
void mysign(int sign)
{
if(sign==SIGCHLD)
{
printf("child is die!\n");
}
}
int main()
{
signal(SIGCHLD,mysign);
pid_t pid=fork();
if(pid ==-1)
{
perror("fork error\n");
exit(1);
}
else if(pid ==0)
{
sleep(2);
printf("I am child!\n");
return 0;
}
else if(pid >0)
{
int ret=pause();
printf("ret==%d\n",ret);
wait(NULL); //回收子进程
printf("my name is father process!\n");
}
return 0;
}