Linux信号处理

信号

  • 由进程的某个操作产生的信号称为同步信息(synchronous signals)
  • 由像用户点击这样的进程外部事件产生的信号叫做异步信号(asynchronous signals)
  • SIGKILL和SIGSTOP既不能忽略也不能被捕捉,进程收到这两个信号只能几首系统的默认处理,即终止进程

signal信号处理机制

1
2
3
4
5
6
#include<signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
//singnum表示要捕捉的信号
//handler是函数指针,表示要对该信号进行捕捉的函数,该参数也可以是SIG_DFL(系统缺省)或者SIG_IGN(忽略该信号不做任何处理)。
//成功返回以前该信号处理函数的地址,否则返回SIG_ERR

sigaction信号处理机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact);
//singnum为需要捕捉的信号
//act是一个结构体,包含信号处理的函数地址,处理方式等信息
//oldact是一个传出参数,sigaction函数调用成功后,oldact里面包含以前对signum的处理方式的信息,通常为NULL
//成功返回0,否则返回-1
struct sigaction{
void (*sa_handler)(int); //老类型的信号处理函数指针
void (*sa_sigaction)(int,siginfo_t *,void*);//新类型的信号处理函数指针
sigset_t sa_mask; //将要阻塞的信号集合
int sa_flags; //信号处理方式掩码(SA_SIGINFO)
void (*da_restorer)(void); //保留,不使用
};
// sa_handler是一个函数指针,用于指向原型为void handler(int)的信号处理函数地址,即老类型的信号处理函数(若再讲sa_flag=0,就等同于signal)
//sa_sigaction是一个函数指针,用于指向原型为:coid handler(int iSignNum,siginfo_t *pSignInfo,void *pReserved);的信号处理函数,即新类型的信号处理函数
//iSignNum:传入的信号;pSignInfo:与该信号相关的一些信息,它是一个结构体;pRserved:保留,通常为NULL
//字段sa_handler和sa_sigaction只应该有一个生效
//采用老信号处理:sa_handler指向正确的信号处理函数,sa_flags为0
//采用新的信号处理机制,sa_sigaction指向正确的信号处理函数,sa_flags包含SA_SIGINFO选项

字段sa_mask是一个包含信号集合的结构体,该结构体内的信号表示在进行信号处理是,将要被阻塞的信号

1
2
3
4
5
6
7
#include<signal.h>
int sigemptyset(sigset_t *set); //清空信号集合set
int sigfillset(sigset_t *set); //将所有信号填充进set中
int sigaddset(sig set_t *set,int signum);//往set中添加信号signum
int sigdelset(sigset_t *set,int signum);//从set中移除信号signum
int sigismember(const sigset_t *set,int signum);//判断signum是够包含在set中(是1否0)
int sigpending(sigset_t *set);//将阻塞的信号集合由参数set指针返回(挂起信号)(系统调用)
sa_flags:

掩码 描述
SA-RESETHAND 处理完毕要捕捉的信号后,将自动撤销信号处理函数的注册,即必须再重新注册信号处理函数,才能继续处理接下来产生的信号。该选项不符合一般的信号处理流程,现已经被废弃
SA_NODEFER 在处理信号时,如果又发生了其他的信号,则立即进入其他信号的处理,等其他信号处理完毕后,在继续处理当前的信号,即递归地处理。(不常用)不断重入,次数不丢失
SA_RESTART 如果发生信号时,程序正阻塞在某个系统调用,例如调用read()函数,则在处理完毕信号后,接着从阻塞的系统返回。如果不指定该参数,中断处理完毕之后,read函数读取失败
SA_SIGINFO 指示结构体的信号处理函数指针是哪个有效,如果sa_flags包含该掩码,则sa_sigaction指针有效,否则是sa_handler指针有效(常用)

sigprocmask信号阻塞

1
2
3
4
5
struct sigaction act;
sigemptyset(&act,sa_mask);
sigaddset(&act.sa_mask,SIGQUIT);
sigaction(SIGINT,&act,NULL):
//只有处理SIGINT信号时,才阻塞SIGQUIT
1
2
#include<signal.h>
int sigprocmask(int how,const digset_t *set,sigset_t *oldset);

how:

参数 说明
SIG_BLOCK 将参数2的信号集合添加进进程原有的阻塞信号集合中
SIG_UNBLOCK 从进程原有的阻塞信号集合移除参数2中包含的信号
SIG_SETMASK 重新设置进程的阻塞信号集为参数2的信号集

set:阻塞信号集 oldset:传出参数,存放进程原有信号集,通常为NULL

用程序发送信号

kill信号

1
2
3
#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid,int sig);
  • pid>0 将信号发给ID为pid的进程
  • pid==0 将信号发给与发送进程属于同一个进程组的所有进程
  • pid<0 将信号发给进程组ID等于pid绝对值的所有进程
  • pid==-1 将信号发给该进程有权限发送的系统的所有进程
  • 成功返回0,失败返回-1

#计时器与信号 ## 睡眠函数

1
2
3
#include<unistd.h>
unsigned int sleep(unsigned int seconds); //秒
void usleep(unsigned long usec); //微秒
1
2
3
4
5
#include<unistd.h>
unsigned int alarm(unsigned int seconds);
//告知自身进程,要进程在seconds秒后自动产生一个SIGALRM信号
int pause(void);
//将自身进程挂起,知道有信号发生时才从pause返回
## 时钟处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<sys/time.h>
int getitimer(int which,struct itimerval *value); //获取计时器的位置
//which:ITIMER_REAL(真实计时器)、ITMER_VIRTUAL(虚拟计时器)、ITIMER_PROF(使用计时器)
int setitimer(int which,const struct itimerval *value,struct itimerval *ovalue);//设置计时器
//value为以结构体的传入参数,指定该计时器的初始间隔时间和重复时间间隔
//ovalue为一结构体传出参数,用于传出以前的计时器时间设置
struct itimerval{
struct timeval it_interval;//next value
struct timeval it_value; //current value
};
struct timeval{
long tv_sec;//seconds
long tv_usec;//microseconds
};