信号是在特定事件发生时由操作系统向进程发送消息。为了响应消息,执行与消息相关的自定义操作时的过程称为“信号处理”。
信号与signal函数
信号注册函数
#include<signal.h>
void(*signal(int signo,void (*func)(int)))(int);
函数名:signal
参数:int signo,void (*func)(int)
返回类型:参数为int型,返回void型函数指针
第一个参数为特殊情况信息,第二个参数为特殊情况下将要调用的函数的地址值。发生第一个参数代表的情况时,调用第二个参数所指的函数。
下面是可以在signal函数中注册的部分特殊情况和对应的常数:
SIGALRM:已到通过调用alarm函数注册的时间
SIGINT:输入CTRL+C
SIGCHLD:子进程终止
下面是信号注册过程:
signal(SIGCHLD,mychild);//子进程终止则调用mychild函数
signal(SIGALRM,timeout);//已到通过alarm函数注册时间,调用timeout函数
signal(SIGINT,keycontrol);//输入CTRL+C时调用keycontrol函数
下面是alarm函数:
#include<unistd.h>
unsigned int alarm(unsigned int seconds);
//返回0或以秒为单位的距SIGALRM信号发生所剩时间
下面是一个示例:
#include<sdtio.h>
#include<unistd.h>
#include<signal.h>
void timeout(int sig)
{
if(sig==SIGALRM)
puts("Time out!");
alarm(2);
}
void keycontrol(int sig)
{
if(sig==SIGINT)
puts("CTRL+C pressed");
}
int main()
{
int i;
signal(SIGALRM,timeout);
signal(SIGINT,keycontrol);
alarm(2);
for(i=0;i<3;i++)
{
puts("wait...");
sleep(100);
}
return 0;
}
发生信号时将唤醒由于sleep函数而进入阻塞状态的进程。调用函数的主体是操作系统,但进程处于睡眠状态时无法调用函数。因此,产生信号时,为了调用信号处理器,将唤醒由于调用sleep函数而进入阻塞状态的进程。
利用sigaction函数进行信号处理
sigaction函数类似于signal函数,而且更稳定。
#include<signal.h>
int sigaction(int signo,const struct sigaction *act,struct sigaction *oldact);
---成功时返回0,失败时返回-1
signo---与signal函数相同,传递信号信息
act----对应于第一个参数的信号处理函数信息
oldact---通过此参数获取之前注册的信号处理函数指针,若不需要则传递0
声明并初始化sigaction结构体变量以调用上述函数,该结构体定义如下:
struct sigaction
{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
}
此结构体的sa_handler成员保存信号处理函数的指针值。sa_mask和sa_flags的所有位均初始化为0即可。这两个成员用于指定信号相关的选项和特性。
下面给出示例:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void timeout(int sig)
{
if(sig==SIGALRM)
puts("Time out!");
alarm(2);
}
int main()
{
int i;
struct sigaction act;
act.sa_handler=timeout;
sigemptyset(&act.sa_mask); //sigemptyset函数将sa_mask成员的所有位初始化为0
act.sa_flags=0;
sigaction(SIGALRM,&act,0);
alarm(2);
for(i=0;i<3;i++)
{
puts("wait...");
sleep(100);
}
return 0;
}
利用信号消灭僵尸进程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
void read_childproc(int sig)
{
int status;
pid_t id=waitpid(-1,&status,WNOHANG);
if(WIFEXITED(status))
{
printf("Removed proc id:%d \n",id);
printf("Child send:%d \n",WEXITSTATUS(status));
}
}
int main()
{
pid_t pid;
struct sigaction act;
act.sa_handler=read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
sigaction(SIGCHLD,&act,0);
pid=fork();
if(pid==0){
puts("Hi!I am child process");
sleep(10);
return 12;
}
else{
printf("Child proc id:%d \n",pid);
pid=fork();
if(pid==0){
puts("Hi!I am child process");
sleep(10);
exit(24);
}
else{
int i;
printf("child proc id:%d \n",pid);
for(i=0;i<5;i++){
puts("wait...");
sleep(5);
}
}
}
return 0;
}