进程间通信有很多种方式,常见的有管道,消息队列,信号量,共享内存,还有信号,这篇文章主要结合实列简单介绍信号函数的使用,以及有哪些常用的信号类型
常用的信号类型有以下几种:
SIGTERM:可以捕捉,默认执行操作是终止程序,终端执行kill 或者 kill -15发送该信号
SIGKILL:不可以捕捉,默认执行操作是终止程序,终端执行kill -9 发送该信号
SIGALRM:定时器超时信号
SIGUSR1,SIGUSR2:用户定义信号
SIGCHLD:子进程退出时发送给发进程的信号
当某个信号出现时,可以告诉内核按下面的3种方式之一进行处理
1. 忽略该信号,大多数信号都可以使用这种方式进行处理,但是SIGKILL和SIGSTOP这两种信号不可以忽略
2. 捕捉信号,这个是通知内核在某种信号产生时,调用一个用户函数,在用户函数中,可执行用户希望对这种事件进行处理
3. 执行系统默认动作,系统对每种信号都有一个默认动作,需要注意的是对大多数信号,系统的默认动作是终止该进程
下面介绍下一个UNIX系统信号机制最简单的接口signal 函数
原型如下
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
下面简单演示下该接口的使用,让signal捕捉两个用户定义的信号并打印信号编号
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
static void sig_usr(int signo)
{
if (SIGUSR1 == signo)
{
printf("received SIGUSR1\n");
exit(0);
}
else if (SIGUSR2 == signo)
{
printf("received SIGUSR2\n");
exit(0);
}
else
{
printf("received signal %d\n", signo);
}
}
int main(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
{
printf("can't catch SIGUSR1\n");
}
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
{
printf("can't catch SIGUSR2\n");
}
for(; ;)
{
sleep(2);
}
return 0;
}
结果如下:
mcchen-virtual-machine:/home/mywork/test/signal$ ./signal & //在后台启动进程
[1] 5472 //作业控制shell打印作业编号和进程ID
mcchen-virtual-machine:/home/mywork/test/signal$ kill -USR1 5472 //向该进程发送SIGUSR1
received SIGUSR1
mcchen-virtual-machine:/home/mywork/test/signal$ kill -USR2 5472 //向该进程发送SIGUSR2
received SIGUSR2
mcchen-virtual-machine:/home/mywork/test/signal$ kill 5472 //向该进程发送SIGTERM
[1]+ Terminated ./signal
/*由于程序并没有捕捉SIGTERM信号,而对该信号的系统默认动作是终止,所以当向该进程发送SIGTERM信号后,该进程就终止*/
SIGKILL和SIGSTOP两个信号捕捉不了,下面通过实例演示下
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
static void sig_usr(int signo)
{
if (SIGUSR1 == signo)
{
printf("received SIGUSR1\n");
}
else if (SIGUSR2 == signo)
{
printf("received SIGUSR2\n");
}
else
{
printf("received signal %d\n", signo);
}
}
int main(void)
{
if (signal(SIGKILL, sig_usr) == SIG_ERR)
{
printf("can't catch SIGKILL\n");
}
if (signal(SIGSTOP, sig_usr) == SIG_ERR)
{
printf("can't catch SIGSTOP\n");
}
for(; ;)
{
sleep(2);
}
return 0;
}
结果如下
mcchen@mcchen-virtual-machine:/home/mywork/test/signal$
can't catch SIGKILL //捕捉不了SIGKILL
can't catch SIGSTOP //捕捉不了SIGSTOP
总结下,这篇文章简单介绍了signal的使用,以及信号的种类,以及SIGKILL和SIGSTOP两个信号不可以忽略或捕捉,其它信号可以忽略捕捉,默认是终止进程,后面有时间会详细介绍signal衍生的其它接口,谢谢。