signal
#include<signal.h>
#include<sys/types.h>
int kill(pid_t pid,int sig)
pid的取值:
正数:要发送信号的进程号
0:信号被发送到所有和 pid 进程在同一个进程组的进程
−1:信号发给所有的进程表中的进程(除了进程号最大的进程外)
int raise(int sig) 进程向自身发送信号
#include <unistd.h>
unsigned int alarm(unsigned int seconds)
alarm当定时器指定的时间到时, 它就向进程发送 SIGALARM 信号。
int pause(void)
挂起进程直到有信号到来,且当信号处理函数返回后pause()才返回-1。
unsigned int sleep(unsigned int seconds);
休息seconds秒后返回;或者被信号中断且信号处理函数返回后sleep()返回0。
所以如果不计较返回值的话,pause()的功能相当于无限期的sleep()。
最简单的函数如:
int main(){
int ret=alarm(5);
pause();
printf(“I have been waken up.\n”);
}
可靠信号(实时信号)和不可靠信号(非实时信号):
一个不可靠信号的处理过程是这样的:如果发现该信号已经在进程中注册,那么就忽略该信号。因此,若前一个信号还未注销又产生了相同的信号就会产生信号丢失。而当可靠信号发送给一个进程时,不管该信号是否已经在进程中注册,都会被再注册一次,因此信号就不会丢失。所有可靠信号都支持排队,而不可靠信号则都不支持排队。
signal()主要用于非实时信号的处理,不支持信号传递信息。
sigaction()可用于实时信号处理,支持信号传递消息。
信号处理函数必须是返回void,有且只有一个int参数。
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
/*自定义信号处理函数 */
void foo(int sig_no) //必须是返回void,有且只有一个int参数
{
if (sig_no == SIGINT) //按下Ctrl+C产生SIGINT信号
printf("I have got SIGINT\n");
if (sig_no == SIGQUIT) //按下Ctrl+\产生SIGQUIT信号
printf("I have got SIGQUIT\n");
}
int main()
{
puts("Waiting for SIGINT or SIGQUIT...");
signal(SIGINT, foo);
signal(SIGQUIT, foo);
pause(); //等待信号到达
return0;
}
sigaction
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
signum:信号的值,可以为除 SIGKILL 及 SIGSTOP 外的任何一个特定有效的信号
act:指向结构 sigaction 的一个实例的指针,指定对特定信号的处理
oldact:保存原来对相应信号的处理
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
通过sa_mask设置信号掩码集。
信号处理函数可以采用void (*sa_handler)(int)或void (*sa_sigaction)(int, siginfo_t *, void *)。到底采用哪个要看sa_flags中是否设置了SA_SIGINFO位,如果设置了就采用void (*sa_sigaction)(int, siginfo_t *, void *),此时可以向处理函数发送附加信息;默认情况下采用void (*sa_handler)(int),此时只能向处理函数发送信号的数值。
sa_falgs还可以设置其他标志:
SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
#define INPUTLEN 100
void inthandler(int);
int main(){
struct sigaction newhandler;
sigset_t blocked; //被阻塞的信号集
char x[INPUTLEN];
newhandler.sa_flags=SA_RESETHAND;
newhandler.sa_handler=inthandler;
sigemptyset(&blocked); //清空信号处理掩码
sigaddset(&blocked,SIGQUIT);
newhandler.sa_mask=blocked;
if(sigaction(SIGINT,&newhandler,NULL)==-1)
perror("sigaction");
else
while(1){
fgets(x,INPUTLEN,stdin); //fgets()会在数据的最后附加"\0"
printf("input:%s",x);
}
}
void inthandler(int signum){
printf("Called with signal %d\n",signum);
sleep(signum);
printf("done handling signal %d\n",signum);
}
Ctrl-C向进程发送SIGINT信号,Ctrl-\向进程发送SIGQUIT信号。
$ ./sigactdemo
^CCalled with signal 2
^\done handling signal 2
Quit (core dumped)
由于把SIGQUIT加入了信号掩码集,所以处理信号SIGINT时把SIGQUIT屏蔽了。当处理完SIGINT后,内核才向进程发送SIGQUIT信号。
$ ./sigactdemo
^CCalled with signal 2
^Cdone handling signal 2
由于设置了SA_RESETHAND,第一次执行SIGINT的处理函数时相当于执行了signal(SIGINT,SIG_DFL),所以进程第二次收到SIGINT信号后就执行默认操作,即挂起进程。
修改代码,同时设置SA_RESETHAND和SA_NODEFER。
newhandler.sa_flags=SA_RESETHAND|SA_NODEFER;
$ ./sigactdemo
^CCalled with signal 2
^C
在没有设置SA_NODEFER时,在处理SIGINT信号时,自动屏幕SIGINT信号。现在设置了SA_NODEFER,则当SIGINT第二次到来时立即响应,即挂起了进程。