基本概念
•又叫:软中断信号,是一种异步通信的IPC
•类似于硬件中断,可以将一个事件以信号形式通知给进程
•给一个指定进程发送一个信号
–信号只是告诉进程发生了什么事,并不传递数据
–进程表的表项中有一个软中断信号域,有信号发给该进程,对应位置位
–进程根据接收信号类型作相应的处理
信号的来源
•来自shell终端用户输入的各种信号:ctrl + C/D
•来自其它进程或者进程本身发送的信号
•来自系统内部的信号
–硬件异常:如SIGBUS表示总线错误、SIGSEGV表示段错误
–终端相关的信号
–软件事件相关的信号
进程对信号的处理方式
–缺省行为
•忽略信号:如SIGIGN、SIGCHLD
–SIGKILL/SIGSTOP比较特殊,不能忽略,所有进程都要在OS管控之下
•终止进程:SIGTERM、SIGINT、SIGHUP
•终止进程并内核转储:SIGBUS、SIGABRT、SIGQUIT
–捕获信号并执行信号注册的handler
•通过signal系统调用可以改变信号的处理行为,即注册新的handler
•当有信号到来时,信号的处理类似于中断程序
•暂停当前进程正在执行的代码、跳到注册的回调函数handler执行
•函数返回,回到当前进程捕获信号的地方继续执行
•若该信号没有注册回调函数,采用默认操作:忽略或终止进程
信号相关API
•typedef void (*sighandler_t)(int);
•sighandler_t signal (int signum, sighandler_t handler);
•int kill (pid_t pid, int sig);
–通过signal注册信号处理函数
–进程之间通过kill发送软中断信号
–内核也可以因内部异常等事件给进程发信号
系统调用signal
•函数原型:sighandler_t signal (int signum, sighandler_t handler);
•函数功能:注册一个信号处理函数
•函数参数
–signum:信号值,定义在:asm/signal.h 头文件中,很多信号跟体系相关
–handler:信号对应的处理函数
–Linux支持的信号列表
系统调用:kill
•函数原型:int kill (pid_t pid, int sig);
•函数功能:给指定进程发送一个信号
系统调用:pause
•函数原型:int pause (void);
•函数功能:将当前进程挂起睡眠,等待某一个信号,直到信号到来,恢复运行
•返回值:该函数总是返回-1
系统调用:alarm
•函数原型:unsigned int alarm(unsigned int seconds);
•函数功能:给当前进程在指定的seconds秒后发送一次SIGALRM信号
系统调用:setitimer
•int getitimer (int which, struct itimerval *curr_value);
•int setitimer (int which, const struct itimerval *new_value,
struct itimerval *old_value);
•函数功能:获取定时器状态、设置定时器,周期发送信号
•函数参数:which,指定三个内部定时器中的一个
–ITIMER_REAL:按实际时间计时,计时到达给进程发送SIGALRM信号
–ITIMER_VIRTUAL:当进程执行时才计时,到期后发送SIGVTALRM信号
–ITIMER_PROF:当进程执行或系统为该进程执行动作时都计时,如统计进程在用户态和内核态所花的时间,到期后发送SIGPROF信号给进程
函数示例
pause
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void signal_handler (int unused)
{
printf ("catch a signal SIGINT\n");
}
int main (void)
{
signal (SIGINT, signal_handler);
pause();
printf ("main exit...\n");
return 0;
}
setitimer
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
void signal_handler (int signum)
{
switch (signum)
{
case SIGALRM:
printf ("catch a signal: SIGALRM\n");
break;
case SIGVTALRM:
printf ("catch a signal: SIGVTALRM\n");
break;
}
return;
}
int main (void)
{
struct itimerval value,old_value, value2;
printf ("process id: %d\n", getpid());
signal (SIGALRM, signal_handler);
signal (SIGVTALRM, signal_handler);
value.it_value.tv_sec = 5;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = 1;
value.it_interval.tv_usec = 0;
setitimer (ITIMER_REAL, &value, &old_value);
value2.it_value.tv_sec = 10;
value2.it_value.tv_usec = 0;
value2.it_interval.tv_sec = 1;
value2.it_interval.tv_usec = 0;
setitimer (ITIMER_VIRTUAL, &value2, &old_value);
while (1)
{
// for(;;);
sleep (5);
}
return 0;
}
signal
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void handler (int signo)
{
switch (signo)
{
case 1:
printf ("get a SIGUP signal: %d\n", signo);
break;
case 2:
printf ("get a SIGINT signal: %d\n", signo);
break;
case 3:
printf ("get a SIGQUIT signal: %d\n", signo);
break;
}
}
int main (void)
{
signal (SIGHUP, handler);
signal (SIGINT, handler);
signal (SIGQUIT, handler);
pause ();
//while (1);
return 0;
}
alarm
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void signal_handler (int unused)
{
printf ("catch a signal SIGALRM\n");
}
int main (void)
{
signal (SIGALRM, signal_handler);
alarm (5);
pause ();
//sleep (3);
//alarm (3);
printf ("main exit\n");
return 0;
}
kill
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
int main (void)
{
while (1)
{
kill (7118, SIGHUP);
sleep (2);
}
return 0;
}
#include <stdio.h>
int main (void)
{
while (1);
return 0;
}