一.信号的分类:
1.kill–l //列举所以信号
2.不可忽略信号: SIGKILL,SIGSTOP。
二.信号的发送:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort()
1. kill
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int signo);
向某个进程发送信号,参数为进程id和信号的值。
调用成功返回0,出错返回-1并设置errno。
Pid>0 | 进程ID为pid的进程 |
Pid = 0 | 同一个进程组的进程 |
Pid<0,pid!=-1 | 进程组ID为-pid的所有进程 |
Pid = -1 | 除发送进程自身外,所有进程ID大于1的进程 |
2. raise
#include <signal.h>
int raise(int signo)
向进程本身发送信号,参数为即将发送的信号值。
调用成功返回 0;否则,返回 -1
3. sigqueue
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
向进程发送信号,比kill()传递多了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组。如果signo=0,将会执行错误检查。
在调用sigqueue时,sigval_t指定的信息会拷贝到sigaction()信号处理函数的siginfo_t结构中。
unionsigval
{
int sival_int;
void *sival_ptr;
};
成功返回0,出错返回-1,并设置errno。
4. alarm
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
专门为SIGALRM信号而设,在指定的时间seconds秒后,将向进程本身发送SIGALRM信号,又称为闹钟时间。
进程调用alarm后,任何以前的alarm()调用都将无效。如果参数seconds为零,那么进程内将不再包含任何闹钟时间。
返回值,如果调用alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。
5. setitimer
include< sys/time.h>
int setitimer(int which, const struct itimerval *new_value, struct itimerval*old_value);
setitimer()比alarm功能强大,支持3种类型的定时器:
ITIMER_REAL:设定绝对时间;经过指定的时间后,内核将发送SIGALRM信号给本进程;
ITIMER_VIRTUAL:设定程序执行时间;经过指定的时间后,内核将发送SIGVTALRM信号给本进程;
ITIMER_PROF:设定进程执行以及内核因本进程而消耗的时间和,经过指定的时间后,内核将发送ITIMER_VIRTUAL信号给本进程;
setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例;第三个参数可不做处理。
返回值:调用成功返回0,否则返回-1。
struct itimerval
{
struct timevalit_interval; /* next value */
struct timevalit_value; /* current value */
};
struct timeval
{
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
6. abort()
#include <stdlib.h>
void abort(void);
向进程本身发送SIGABORT信号,默认情况下进程会异常退出,当然可定义自己的信号处理函数。即使SIGABORT被进程设置为阻塞信号,调用abort()后,SIGABORT仍然能被进程接收。该函数无返回值。
三.信号的安装:
1、signal()
#include <signal.h>
void(*signal(int signum, void (*handler))(int)))(int);
可以参考下面的分解方式来理解:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler));
第一个参数指定信号的值,第二个参数指定针对前面信号值的处理,可以忽略该信号(参数设为SIG_IGN);可以采用系统默认方式处理信号(参数设为SIG_DFL);也可以自己实现处理方式(参数指定一个函数地址)。
如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR。
2、sigaction()
#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
第一个参数是信号值,第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等。
sigaction结构定义如下:
structsigaction
{
#ifdef__USE_POSIX199309
union
{
__sighandler_t sa_handler;
void (*sa_sigaction) (int, siginfo_t *, void*);
}
__sigaction_handler;
#define sa_handler __sigaction_handler.sa_handler
#define sa_sigaction __sigaction_handler.sa_sigaction
#else
__sighandler_t sa_handler;
#endif
__sigset_t sa_mask;
int sa_flags;
void (*sa_restorer) (void);
};
typedef void (*__sighandler_t) (int);
四.信号集
信号集被定义为一种数据类型:
typedefstruct
{
unsigned long sig[_NSIG_WORDS];
}sigset_t;
相关函数:
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum)
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
//sigemptyset初始化由set指定的信号集,信号集里面的所有信号被清空;
//sigfillset调用该函数后,set指向的信号集中将包含linux支持的64种信号;
//sigaddset在set指向的信号集中加入signum信号;
//sigdelset在set指向的信号集中删除signum信号;
//sigismember判定信号signum是否在set指向的信号集中。
五,信号阻塞和挂起
每个进程都有一个用来描述哪些信号递送到进程时将被阻塞的信号集,该信号集中的所有信号在递送到进程后都将被阻塞。下面是与信号阻塞相关的几个函数:
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset));
int sigpending(sigset_t *set));
int sigsuspend(const sigset_t *mask));
sigprocmask()函数能够根据参数how来实现对信号集的操作,操作主要有三种:
■SIG_BLOCK :在进程当前阻塞信号集中添加set指向信号集中的信号
■SIG_UNBLOCK:如果进程阻塞信号集中包含set指向信号集中的信号,则解除对该信号的阻塞
■SIG_SETMASK:更新进程阻塞信号集为set指向的信号集
sigpending()获得当前已递送到进程,却被阻塞的所有信号,在set指向的信号集中返回结果。
sigsuspend()用于在接收到某个信号之前, 临时用mask替换进程的信号掩码, 并暂停进程执行,直到收到信号为止。sigsuspend 返回后将恢复调用之前的信号掩码。信号处理函数完成后,进程将继续执行。该系统调用始终返回-1,并将errno设置为EINTR。