一、信号概念
信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程间通信机制中唯一的异步通信机制,可以
看作是异步通知,通知接收信号的进程有哪些事情发生了.信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息.
二、信号的使用
2.1 信号的安装
#include <signal.h>
void (*signal(int signum, void (*handler))(int)))(int);
功能:实现信号和信号处理函数的绑定
举例:signal(SIGUSR1,func);
#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
参数:signum信号值;可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号
参数:act信号的处理设置;其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等
参数:oldact信号以前的设置
struct sigaction {
union{
__sighandler_t _sa_handler;//信号处理函数或者SIG_DEL、SIG_IGN
void (*_sa_sigaction)(int,struct siginfo *, void *);//带参数的信号处理函数
}_u
sigset_t sa_mask;//信号处理程序执行过程中,哪些信号应当被阻塞,缺省情况下当前信号本身被阻塞,防止信号的嵌套发送
unsigned long sa_flags;//标志
void (*sa_restorer)(void);
}
sa_flags常用值如下:
SA_NODEFER
SA_NOMASK 消息处理期间,不屏蔽本身
SA_SIGINFO 信号附带数据
SA_RESETHAND 消息处理重置
2.2 信号的发送
发送信号的主要函数有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort().
int kill()
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid,int signo)
参数:pid信号的接收进程
pid>0 进程ID为pid的进程
pid=0 同一个进程组的进程
pid<0 pid!=-1 进程组ID为 -pid的所有进程
pid=-1 除发送进程自身外,所有进程ID大于1的进程
参数:signo是信号值,当为0时(即空信号),实际不发送任何信号,但照常进行错误检查,因此,可用于检查目标进程是否存在,以及当前进程是否具有向目标发送信号的权限(
root权限的进程可以向任何进程发送信号,非root权限的进程只能向属于同一个session或者同一个用户的进程发送信号).
返回值:成功返回 0; 否则返回 -1
#include <signal.h>
int raise(int signo)
向进程本身发送信号
参数:signo为即将发送的信号值
返回值:调用成功返回 0;否则,返回 -1.
#include <sys/types.h>
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval val)
参数:pid信号的接收进程
参数:sig信号值
参数:val附加的消息
返回值:调用成功返回 0;否则,返回 -1.
sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然也支持前32种),支持信号带有参数,与函数sigaction()配合使用.
typedef union sigval {
int sival_int;
void *sival_ptr;
}sigval_t;
sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组.
int alarm()
#include <unistd.h>
unsigned int alarm(unsigned int seconds)
功能:在指定的时间seconds秒后,将向进程本身发送SIGALRM信号,又称为闹钟时间.进程调用alarm后,任何以前的alarm()调用都将无效.如果参数seconds为零,那么进程内将
不再包含任何闹钟时间.
参数:seconds闹钟时间
返回值:如果调用alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0.
int setitimer()
#include <sys/time.h>
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
参数: which定时器类型
setitimer()比alarm功能强大,支持3种类型的定时器:
ITIMER_REAL: 设定绝对时间;经过指定的时间后,内核将发送SIGALRM信号给本进程;
ITIMER_VIRTUAL 设定程序执行时间;经过指定的时间后,内核将发送SIGVTALRM信号给本进程;
ITIMER_PROF 设定进程执行以及内核因本进程而消耗的时间和,经过指定的时间后,内核将发送ITIMER_VIRTUAL信号给本进程;
参数:value定时器时间
参数:ovalue定时器以前的时间
返回值:成功返回0,否则返回-1.
int abort()
#include <stdlib.h>
void abort(void);
功能:向进程发送SIGABORT信号,默认情况下进程会异常退出,当然可定义自己的信号处理函数.即使SIGABORT被进程设置为阻塞信号,调用abort()后,SIGABORT仍然能被进程接
收.该函数无返回值.
2.3 信号的响应
进程可以通过三种方式来响应一个信号:(1)忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL及SIGSTOP;(2)捕捉信号.定义信号处理函数,当信号发生时,执行相应的处理函数;(3)执行缺省操作,Linux对每种信号都规定了默认操作,详细情况请参考[2]以及其它资料.注意,进程对实时信号的缺省反应是进程终止.Linux究竟采用上述三种方式的哪一个来响应信号,取决于传递给相应API函数的参数.
三、应用举例
实例1:实现一个信号接收程序
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
struct sigaction act;
int sig;
sig=atoi(argv[1]);
sigemptyset(&act.sa_mask);
act.sa_flags=SA_SIGINFO;
act.sa_sigaction=new_op;
if(sigaction(sig,&act,NULL) < 0)
{
printf("install sigal error\n");
}
while(1)
{
sleep(2);
printf("wait for the signal\n");
}
}
void new_op(int signum,siginfo_t *info,void *myact)
{
printf("receive signal %d", signum);
sleep(5);
}
实例2:信号传递附加信息
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
struct sigaction act;
union sigval mysigval;
int i;
int sig;
pid_t pid;
char data[10];
memset(data,0,sizeof(data));
for(i=0;i <10;i++)
data[i]='2';
mysigval.sival_ptr=data;
sig=atoi(argv[1]);
pid=getpid();
sigemptyset(&act.sa_mask);
act.sa_sigaction=new_op;//参数信号处理函数
act.sa_flags=SA_SIGINFO;//信息传递开关
if(sigaction(sig,&act,NULL) < 0)
{
printf("install sigal error\n");
}
while(1)
{
sleep(2);
printf("wait for the signal\n");
sigqueue(pid,sig,mysigval);//向本进程发送信号,并传递附加信息
}
}
void new_op(int signum,siginfo_t *info,void *myact)//信号处理函数的实现
{
int i;
for(i=0;i<10;i++)
{
printf("%c\n ",(*( (char*)((*info).si_ptr)+i)));
}
printf("handle signal %d over;",signum);
}
参考文章:
http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html