转自:http://zhangcy.anytome.com/20060321121911820418131452020050715/35.xml
一 入门
信号是有雷同的或不同的历程向一个历程递交的事件。信号等闲用来向一个历程通知失常事件。
术语:
发生(generate):当导致信号发生的事件揭示时,例如硬件失常,就发生一个针对某个历程的信号
递交(deliver): 当历程对发给它的信号历程处理时,称为改信号被递交。
未决(pending):发生信号和递交信号之间的工夫间隔称为信号未决。
安排(disposition):历程如何响应信号,历程能够疏忽(ignore),厉行默认垄断可能利用自定义代码处理该信号。
linux 按照POSIX.1告终了可靠信号语义 (关于可靠信号与不可靠信号请比照AUPE)。linux
还告终了POSIX.4定义的real-time signals. 号召(kill –l)
能够揭示Linux下所有信号。规范信号和实时信号的差异如下:
规范信号
实时信号
所有信号曾经定义
未定义(前3个已被linuxpthreads-利用)
不能排队(递交前无论发生多少个信号,接受历程只收到一个)。
能够排队 (/proc/sys/kernel/rtsig-max 揭示队列长度)
不能携带其他数据
能够携带其他数据
不能保证时序
保证时序
万一同时有规范信号和实时信号,Linux先处理规范信号
信号处理编程
最容易的信号处理
#include
#include
static void sig_usr(int);
int main()
{
if(signal(SIGUSR1,sig_usr)==SIG_ERR)
perror("cant catch sigusr1");
for(;;)
pause();
return 0;
}
static void sig_usr(int signo)
{
if(signo==SIGUSR1)
printf("recv SIGUSR1/n");
return ;
}
过程运行后,在shell里用号召(kill –USR1 pid )
向过程发送信号,过程就会输出“recv
SIGUSR1”。
这个过程揭示了信号处理的大约过程,率先我们利用signal函数安排了SIGUSR1信号的处理函数,用我们定义的sig_usr轮换了默认函数。然后调用pause使该历程挂起,期待该历程捉拿信号。当历程收到了我们发送的USR1信号是sig_usr就被调用,pause归来,由于是死循环该历程又挂起。
这个过程有一点要解释,signal函数是不评比利用的,因为signal是ANSI
C定义的它对信号的处理的定义极其笼统,全面依靠于垄断系统。有的系统(SVR4)告终的不可靠语义,而BSD告终的是可靠语义。Linux内核和libc4,5和SVR4雷同,而glibc2和BSD雷同,在我的机器上是可靠语义的,鬼才懂得你机器上什么样子。然而因为它容易,因而都拿来入门。
要写过程还是要利用sigset_t相干函数和sigaction,sigprocmask,sigsuspend,sigpendingwww.e4bs.com.
sigset_t 有5个相干函数离别是:
sigemptyset(sigset_t *set); 初始化set指向的信号集,使其打扫所有信号
sigfillset(sigset_t *set); 初始化set指向的信号集,使其包括所有信号。
sigaddset(sigset_t *set ,int signo); 将一个信号增加到现存信号凑近
sigdelset(sigset_t *set,int signo); 从现存信号凑近剔除一个信号
sigismemberset(const sigset_t *set,int signo);
查询一个信号是否在信号凑近。
sigaction 察看或修正与指定信号相干的处理动作。
sigprocmask 察看或修正与指定信号的屏障字
sigsuspend 在一个原子早在中告终还原信号屏障字,然后使历程睡眠。
sigpending 归来对于调用历程被阻塞不能递交和目前未裁决的信号集。
利用sigaction的过程:
#include
#include
static void sig_usr(int);
int main()
{
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_handler=sig_usr;
sigaction(SIGUSR1,&action,NULL);
for(;;)
pause();
return 0;
}
static void sig_usr(int signo)
{
if(signo==SIGUSR1)
printf("recv SIGUSR1/n");
return ;
}
sigaction的原型是:
int sigaction(int signum,const struct sigaction *act,struct
sigaction *oldact);
为指定的signum设可信号处理过程,act
是新的信号安排,oldact归来本来的信号安排。sigaction定义如下:
struct sigaction {
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
sa_handler是函数指针,指向信号处理函数,也能够是SIG_DEL(设置成默认动作)可能SIG_IGN(疏忽该信号)。sa_mask定义了在指向处理其间该当阻塞的其他信号聚集的掩码。
sa_flags修正sa_handler的行动,能够下面几个值之一:
SA_NOCLDSTOP 历程疏忽子历程发生的任何SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
SA_ONESHOT 登记的自定义信号处理过程仅厉行顺次。厉行告终后还原默认动作。
SA_RESTART 让可重启的系统调用起作用
SA_NOMASK 不避免在信号自己的处理过程中接受信号本身。
sa_restorer曾经被丢弃。
实时信号编程
// rtsig.c
#include
#include
static void sig_proc(int,siginfo_t *,void *);
int main()
{
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_sigaction=sig_proc;
action.sa_flags=SA_SIGINFO;
sigaction(SIGRTMIN+5,&action,NULL);
pause();
return 0;
}
static void sig_proc(int signo,siginfo_t *info,void *p)
{
if(signo==SIGRTMIN+5)
{
int val=info->si_value.sival_int;
// int val=*((int *)info->si_value.sival_ptr);
will be error
printf(da.danbell.com"recv value %d/n",val);
printf("sender pid %d/n",info->si_pid);
printf("signo %d/n",info->si_signo);
}
return ;
}
信号处理过程有两点改变,率先信号处理的接口改变了增加了两个参数,重要的是第二个参数siginfo_t (定义比照man
sigaction),它包括了许多消息,包括发送消息的PID,UID,信号携带的数据。其次sa_flags设成了SA_SIGINFO,只有这么处理过程能力接收到信号携带的数据。
// sendsig.c
#include
#include
int main()
{
int pid,val;
printf("input pid and value :");
scanf("%d %d",&pid,&val);
union sigval sigv;
sigv.sival_int=val; //sigv.sival_ptr=(void
*)&val; will be error
sigqueue(pid,SIGRTMIN+5,sigv);
printf("pid is %d/n",getpid());
return 0;
}
这里发送信号改成了sigqueue, sigval携带信号的数据,比照(man sigqueue)。
过程运行收获:
sendmsg:
input pid and value :24479 232
pid is 24482
rtsig:
recv value 232
sender pid 24482
signo 39起源:
本文就常见的Java代码中轻率揭示的问题提出一些创立性提倡,