信号及信号处理

信号(signal)是一种软件中断,它提供了一种处理异步事件的方法,也是进程间惟一的异步通信方式。在

Linux系统中,根据POSIX标准扩展以后的信号机制,不仅可以用来通知某种程序发生了什么事件,还可以给

进程传递数据。

一、信号的来源

    信号的来源可以有很多种试,按照产生条件的不同可以分为硬件和软件两种。

1、 硬件方式

    当用户在终端上按下某键时,将产生信号。如按下组合键后将产生一个SIGINT信号。

硬件异常产生信号:除数据、无效的存储访问等。这些事件通常由硬件(如:CPU)检测到,并将其通知给Linux

操作系统内核,然后内核生成相应的信号,并把信号发送给该事件发生时正在进行的程序。

2、 软件方式

用户在终端下调用kill命令向进程发送任务信号。

进程调用kill或sigqueue函数发送信号。

当检测到某种软件条件已经具备时发出信号,如由alarm或settimer设置的定时器超时时将生成SIGALRM信号。

1、可靠信号与不可靠信号

    在Linux系统中,信号的可靠性是指信号是否会丢失,或者说该信号是否支持排除。SIGHUP( 1 ) ~ 

SIGRTMIN(33) ~ SIGRTMAX(64)之间的信号,它们都是可靠信号,也称为实时信号。

内核设置了这个标志,我们就说内核向一个进程递送了一个信号。信号产生(generate)和递送(delivery)之间

的时间间隔,称主信号未决(pending)。

    进程可以调用sigpending将信号设为阻塞,如果为进程产生一个阻塞信号,而对信号的动作是捕捉该信号(即不忽

略信号), 则内核将为该进程的此信号保持为未决状态,直到该进程对此信号解除阻塞或者对此信号的响应

更改为忽略。如果在进程解除对某个信号的阻塞之前,这种信号发生 了多次,那么如果信号被递送多次(即

信号在未决信号队列里面排队),则称之为可靠信号;只被递送一次的信号称为不可靠信号。

2、信号的优先级

    信号实质上是软中断,中断有优先级,信号也有优先级。如果一个进程有多个未决信号,则对于同一个未决的

实时信号,内核将按照发送的顺序来递送信号。如果存在多个未决信号,则值(或者说编号)越小的越先被递送。

如果即存在不可靠信号,又存在可靠信号(实时信号),虽然POSIX对这一情况没有明确规定,但Linux系统

和大多数遵循POSIX标准的操作系统一样,将优先递送不可靠信号。

三、进程对信号的响应

当信号发生时,用户可以要求进程以下列3种方式之一对信号做出响应。

1、  捕捉信号:对于要捕捉的信号,可以为其指定信号处理函数,信号发生时该函数自动被调用,在该函数内部实

现对该信号的处理。

2、  忽略信号:大多数信号都可使用这种方式进行处理,但是SIGKILL和SIGSTOP这两个信号不能被忽略,同时

这两个信号也不能被捕获和阻塞。此外,如果忽略某某些由硬件异常产生的信号(如非法存储访问或除以0),

则进程的行为是不可预测的。

3、  按照系统默认方式处理。大部分信号的默认操作是终止进程,且所有的实时信号的默认动作都是终止进程。

四、各种信号的默认处理情况

程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP

不能恢复至默认动作的信号有:SIGILL,SIGTRAP

默认会导致进程流产的信号有:SIGABRT、SIGBUS、SIGFPE、SIGILL、SIGIOT、SIGQUIT、SIGSEGV、

SIGTRAP、SIGXCPU、SIGXFSZ

默认会导致进程退出的信号有:SIGALRM、SIGHUP、SIGINT、SIGKILL、SIGPIPE、SIGPOLL、SIGPROF、

SIGSYS、SIGTERM、SIGUSR1、SIGUSR2、SIGVTALRM

默认会导致进程停止的信号有:SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU

默认进程忽略的信号有:SIGCHLD、SIGPWR、SIGURG、SIGWINCH

五、信号处理函数与相关结构

1.信号安装

1.signal() 
    include 

    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 

int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));

sigaction函数用于改变进程接收到特定信号后的行为。该函数的第一个参数为 信号的值,可以为除SIGKILL及

SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。第二

个参数是指 向结构sigaction的一个实例的指针,在结构sigaction的实例中,指定了对特定信号的处理,可

以为空,进程会以缺省方式对信号处理;第三个 参数oldact指向的对象用来保存原来对相应信号的处理,可

指定oldact为NULL。如果把第二、第三个参数都设为NULL,那么该函数可用于检查 信号的有效性。

2、发送信号函数
(1) int raise(int sig); 对当前进程发送指定信号

       (2) int pause(void);  将进程挂起等待信号

       (3) int kill(pid_t pid,int sig); 通过进程编号发送信号

       (4) unsigned int alarm(unsigned int seconds); 指定时间(秒)发送SIGALRM信号。

 seconds 为0 时取消所有已设置的alarm请求;

       (5)int sigqueue(pid_t pid,int sig,const union sigval val);类似于kill函数,多了附

带共用体 union sigval形数,将共用体中的成员 int sival_int 或 void *sival_ptr 的值传递给 信

号处理函数中

的定义类型 siginfo_t 中的 int si_int 或 void *si_ptr;

       (6)int setitimer(int which,const struct itimerval *value,struct itimerval 

*oldvalue);  可定时发送信号,根据which可指定三种信号类型:SIGALRM、SIGVTALRM 和 SIGPROF;作

用

时间也因which值不同而不同;struct itimerval 的成员 it_interval定义间隔时间,it_value 为0

时,使计时器

失效;

       (7) void abort(void) 将造成进程终止;除非捕获SIGABORT信号;  

3、信号集及信号集操作

sigfillset(sigset_t *set); 设置所有的信号到set信号集中;

sigemptyset(sigset_t *set); 从set信号集中清空所有信号;

sigaddset(sigset_t *set,int sig);在set信号集中加入sig信号;

sigdelset(sigset_t *set,int sig);在set信号集中删除sig信号;

4、阻塞信号相关函数

              int sigprocmask(int how,const sigset_t *set,sigset_t *set);  根据how

值,设置阻塞信号集,或释放阻塞的信号集

              int sigpending(sigset_t *set); 获取在阻塞中的所有信号;

              int sigsuspend(const sigset_t *set);    类似于 pause()函数!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值