信号是非常重要的一种进程通信机制,模拟硬件中断,当某个事件发生后,Linux内核通过发信号通知进程去处理,打断进程的执行,比如在i.mx6ull终结者使用文档/ Linux异步通知实验中就使用了信号机制。
信号机制使用一些系统调用在内核注册信号,事件发送后发送信号,进程收到信号后会进行处理,处理方式有以下三种:
1.默认方式(通常是终止进程),
2.忽略,不进行任何操作。
3.捕捉并处理调用信号处理器(回调函数形式)。
本章只关注在应用层对信号的处理,如果想进一步体验信号可以在驱动章节体验异步通知。在Ubuntu终端输入kill -l
,查看所有的信号,具体可查看Linux异步通知实验章节:
- SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
- SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
- SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
- SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
- SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
- SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
- SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
下面是几个常用的函数:
信号处理函数:
signal()
:改变收到信号后的动作。
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
函数功能:信号signum发送后执行 handler。
参数含义:
signum:要捕获的信号类型。
handler:对信号的处理操作,三种处理方式如下:
忽略该信号,填写“SIG_IGN”;
采用系统默认方式处理该信号,填写“SIG_DFL”;
捕获到信号后执行此函数内容,定义格式为“typedef void (*sighandler_t)(int)”,sighandler_t代表一个函数指针。
返回值:调用成功返回最后一次注册信号调用signal()时的handler值;失败返回SIG_ERR。
kill()
:发送信号
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
参数含义:
pid:大于0,时为向PID为pid的进程发送信号;
等于0,向同一个进程组的进程发送信号;
等于-1,除发送进程自身外,向所有进程ID大于1的进程发送信号。
小于-1,向组ID等于该pid绝对值的进程组内所有进程发送信号。
sig:设置发送的信号;等于0时为空信号,无信号发送。常用来进行错误检查。
返回值:执行成功时,返回值为0;错误时,返回-1,并设置相应的错误代码errno。
raise()
:向进程自身发送信号:
#include <signal.h>
int raise(int sig);
sig:信号。
函数功能:相当于kill(getpid(),sig)。
pause()
:暂停进程,等待信号中断。
#include <unistd.h>
int pause(void);
返回值:进程被信号中断后一直返回-1,
函数功能:将进程挂起,等待信号。
alarm()
:定时
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
参数含义:设定的时间
函数功能:设定的时间超过后产生SIGALARM信号,默认动作是终止进程。
使用规则:每个进程只能有一个alarm()函数,时间到后要想再次使用要重新注册。
实验1代码:路径为:11_Linux系统开发进阶\Linux系统编程_章节使用资料。
在程序中实现:改变终端窗口大小三次终止进程。
signal.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
int count=0;
void winHandle(int sig)
{
printf("window change %d !\n",count);
if(sig == SIGWINCH){ //如果窗口大小改变次数+1
count++;
}
if(count ==3){//如果改变三次,程序结束。
raise(SIGKILL);
}
}
int main(int argc, const char *argv[])
{
signal(SIGWINCH,winHandle);//信号SIGWINCH发生后执行winHandle函数
while(1)
sleep(5);
return 0;
}
编译运行,拖到窗口,会看到打印信息,接收三次信号后程序结束:
实验2代码在alarm.c:路径为:11_Linux系统开发进阶\Linux系统编程_章节使用资料。
改变对 alarm定时到后SIGALRM信号的处理,
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void timeOut(int sig)
{
printf("topeet\n");
alarm(2);
}
int main(int argc, const char *argv[])
{
alarm(2);
signal(SIGALRM,timeOut);
while(1);
return 0;
}
不调用signal()时,时间到后进程退出。
调用signal()改变对alarm超时信号的处理,时间到后再次定时,效果如下: