博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unix环境变量--信号(一)
阅读量:2195 次
发布时间:2019-05-02

本文共 6885 字,大约阅读时间需要 22 分钟。

信号是进程间通信机制中唯一的异步通信机制,在实现上是一种软中断,信号可以导致一个正在运行的进程被中断,进而处理一个突发事件。Linux在/usr/include/asm-generic/signal.h中详细定义了信号的信号值,其内容如下:

#define SIGHUP       1      //连接断开   #define SIGINT       2      //终端中断符#define SIGQUIT      3      //终端退出符#define SIGILL       4      //非法硬件指令#define SIGTRAP      5      //硬件故障#define SIGABRT      6      //异常终止#define SIGIOT       6      //硬件故障 #define SIGBUS       7      //硬件故障#define SIGFPE       8      //算术异常#define SIGKILL      9      //终止#define SIGUSR1     10      //紧急情况#define SIGSEGV     11      //无效存储访问#define SIGUSR2     12      //用户自定义信号#define SIGPIPE     13      //写至无读进程的管道#define SIGALRM     14      //超时#define SIGTERM     15      //终止进程#define SIGSTKFLT   16      #define SIGCHLD     17      //子进程改变工作状态#define SIGCONT     18      //使暂定状态的进程继续工作#define SIGSTOP     19      //使进程暂停工作#define SIGTSTP     20      //终端挂起符作业#define SIGTTIN     21      //后台从控制tty读作业#define SIGTTOU     22      //后台从控制tty写作业#define SIGURG      23      //紧急情况#define SIGXCPU     24      //超过CPU限制#define SIGXFSZ     25      //超出文件长度限制#define SIGVTALRM   26      //虚拟时间闹钟#define SIGPROF     27      //时间超时#define SIGWINCH    28      //终端窗口大小改变#define SIGIO       29      //异步I/O#define SIGPOLL     SIGIO**/*#define SIGLOST     29*/#define SIGPWR      30       //电源失效/再启动#define SIGSYS      31       //无效系统调用#define SIGUNUSED   31/* These should not be considered constants from userland.  */#define SIGRTMIN    32#ifndef SIGRTMAX#define SIGRTMAX    _NSIG#endif

下面介绍几中常见信号处理方式:

(1)SIGCHLD在子进程退出时,将发送该信号给父进程,父进程可根据该信号完成对子进程PCB资源的回收。
(2)SIGSTOP、SIGKILL不能被屏蔽、安装。
(3)SIGSTOP和SIGCOUNT是配对的,一个进程收到SIGSTOP后会暂停执行,并屏蔽除SIGKILL外所有信号,在收到SIGCOUNT后,才会继续执行
(4)信号可以唤醒处于sleep()的进程
 

信号的基本术语:

    发送信号:产生信号,并将信号发送出去。

    安装中断:设置信号到来时,不是执行默认操作,而是执行自己自定义的代码。
    递送信号:一个信号被操作系统发送到目标进程。
    捕获信号:被递送的信号在目标进程中引起某段代码的执行。
    屏蔽信号:进程告诉操作系统暂时不接收某些信号。
    忽略信号:进程被递送到目标进程,但目标进程不做任何操作,直接丢弃
    未决信号:信号已经产生,但目标进程暂时屏蔽了该信号,从而导致不能被目标进程捕获的信号。
    可靠信号:信号值大于32的为信号
    不可靠信号:信号值小于32的信号
 

信号开发注意事项:

1、一个进程在执行exec()函数时,因为原先的信号捕捉函数的地址在新程序文件内已无意义,所以,新程序会将原先程序的信号全部改为默认处理方式

2、fork()时,子进程继承父进程的信号处理方式

3、通常将信号编号为0的信号称为空信号,用与kill函数配合用来检测某进程是否存在(非原子操作)

4、在进入信号处理程序的时候,我们总是先屏蔽当前的信号,以避免在执行这个信号处理程序的时候又收到了一模一样的信号。

5、使用排队信号必须满足以下3点:

(1)使用sigaction函数安装信号处理函数时指定SA_SIGINFO标志,如果没有这个标志,信号会延迟

(2)在sigaction结构的sa_sigaction成员中,而不是通常的sa_handler字段,提供信号处理函数

(3)使用sigqueue()函数发送信号

常用函数:

信号安装:

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler));

参数:第一个参数指定信号的值,第二个参数指定针对前面信号值的处理,可以忽略该信号(参数设为SIG_IGN);可以采用系统默认方式处理信号(参数设为SIG_DFL);也可以自己实现处理方式(参数指定一个函数地址)。

头文件:#include <signal.h>

返回值:如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR。

信号发送:

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

作用:sigaction函数用于改变进程接收到特定信号后的行为。

参数:第一个参数为信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。

第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理;

第三个参数oldact指向的对象用来保存返回的原来对相应信号的处理,可指定oldact为NULL。

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

第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些信号等等。

sigaction结构定义如下:struct sigaction {       

               union{          

                      _sighandler_t _sa_handler;                                                                                                                                                                                void (*_sa_sigaction)(int,struct siginfo*,void*);}_u          

                         sigset_t sa_mask;        

                         unsigned long sa_flags;} 

  1、联合数据结构中的两个元素_sa_handler以及*_sa_sigaction指定信号关联函数,即用户指定的信号处理函数。除了可以是用户自定义的处理函数外,还可以为SIG_DFL(采用缺省的处理方式),也可以为SIG_IGN(忽略信号)。 

2、由_sa_sigaction是指定的信号处理函数带有三个参数,是为实时信号而设的(当然同样支持非实时信号),它指定一个3参数信号处理函数。第一个参数为信号值,第三个参数没有使用,第二个参数是指向siginfo_t结构的指针,结构中包含信号携带的数据值。

参数所指向的结构如下:siginfo_t {         

                 int      si_signo;  /* 信号值,对所有信号有意义*/           

                  int      si_errno;  /* errno值,对所有信号有意义*/            

                   int      si_code;   /* 信号产生的原因,对所有信号有意义*/                          

                   union{                               /* 联合数据结构,不同成员适应不同信号 */   

                                         int _pad[SI_PAD_SIZE];        //确保分配足够大的存储空间

                                   struct{                                                      ...                                                 }...                                               .../对SIGILL, SIGFPE, SIGSEGV, SIGBUS有意义的结构                                  struct{            }...      .. ...              }}

 前面在讨论系统调用sigqueue发送信号时,sigqueue的第三个参数就是sigval联合数据结构,当调用sigqueue时,该数据结构中的数据就将拷贝到信号处理函数的第二个参数中。这样,在发送信号同时,就可以让信号传递一些附加信息。信号可以传递信息对程序开发是非常有意义的。 

3、sa_mask指定在信号处理程序执行过程中,哪些信号应当被阻塞。缺省情况下当前信号本身被阻塞,防止信号的嵌套发送,除非指定SA_NODEFER或者SA_NOMASK标志位。注:请注意sa_mask指定的信号阻塞的前提条件,是在由sigaction()安装信号的处理函数执行过程中由sa_mask指定的信号才被阻塞。 

4、sa_flags中包含了许多标志位,包括刚刚提到的SA_NODEFER及SA_NOMASK标志位。另一个比较重要的标志位是SA_SIGINFO,当设定了该标志位时,表示信号附带的参数可以被传递到信号处理函数中,因此,应该为sigaction结构中的sa_sigaction指定处理函数,而不应该为sa_handler指定信号处理函数,否则,设置该标志变得毫无意义。即使为sa_sigaction指定了信号处理函数,如果不设置SA_SIGINFO,信号处理函数同样不能得到信号传递过来的数据,在信号处理函数中对这些信息的访问都将导致段错误(Segmentation fault)。 

头文件:#include <signal.h>

 int kill(pid_t pid,int signo);

头文件:#include <sys/types.h>

#include <signal.h>

参数:参数pid的值为信号的接收进程

pid>0  进程ID为pid的进程

pid==0 同一个进程组的进程

pid<0&&pid != -1 进程组ID为 -pid的所有进程

pid == -1 除发送进程自身外,所有进程ID大于1的进程

作用:该系统调用可以用来向任何进程或进程组发送任何信号。

 int raise(int signo)

头文件:#include <signal.h>

作用:向进程本身发送信号,参数为即将发送的信号值。

返回值:调用成功返回 0;否则,返回 -1。

 unsigned int alarm(unsigned int seconds);

头文件:#include <unistd.h>

作用:系统调用alarm安排内核为调用进程在指定的seconds秒后发出一个SIGALRM的信号。

参数:如果指定的参数seconds为0,则不再发送 SIGALRM信号。后一次设定将取消前一次的设定。

返回值:为上次定时调用到发送之间剩余的时间,若第一次没调用则返回0。

void abort(void);

头文件:#include <stdlib.h>

作用:向进程发送SIGABORT信号,默认情况下进程会异常退出,当然可定义自己的信号处理函数。即使SIGABORT被进程设置为阻塞信号,调用abort()后,SIGABORT仍然能被进程接收。该函数无返回值。

int pause(void);

头文件:include<unist.h>

作用:使进程挂起,直到捕捉到一个信号为止

int sigqueue(pid_t pid, int sig, const union sigval val);

返回值:调用成功返回 0;否则,返回 -1。

参数:pid:接收信号的进程ID

sig:即将发送的信号

val:是一个联合数据结构union sigval,指定了信号传递的参数

信号集及信号集操作函数:

int sigemptyset(sigset_t *set);  初始化由set指定的信号集,信号集里面的所有信号将被清空;

int sigfillset(sigset_t *set);调用该函数后,set指向的信号集中将包含linux支持的64种信号;

int sigaddset(sigset_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指向的信号集中。

头文件:#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(sigset_t *set))获得当前已递送到进程,却被阻塞的所有信号,在set指向的信号集中返回结果。 

sigsuspend(const sigset_t *mask))用于在接收到某个信号之前, 临时用mask替换进程的信号掩码, 并暂停进程执行,直到收到信号为止。sigsuspend 返回后将恢复调用之前的信号掩码。信号处理函数完成后,进程将继续执行。该系统调用始终返回-1,并将errno设置为EINTR。

头文件:#include <signal.h>

信号高级用法:

int sigsetjmp(sigjmp_buf env, int savemask);

vodi siglongjmp(sigjmp_buf env, int val);

头文件:#include <setjmp.h>

作用:用法都与setjmp和longjmp非常接近。只是多了一个savemask参数:

0:不保存、不恢复屏蔽字,即因为信号处理函数加入的信号不会因为信号处理函数返回而被恢复;非0:代表需要保存、恢复屏蔽字。屏蔽字也同样保存在env中。

休眠函数:

unsigned int sleep(unsigned int seconds);

头文件:#include<unistd.h>

返回值:成功则返回0,若有信号中断则返回剩余秒数。

int nanosleep(const struct timespec *req, struct timespec *rem);

头文件:#include<time.h>

返回值:成功则返回0,若有信号中断则返回-1

参数说明:第一个参数req保存的是,休眠的时间长,第二个参数保存的是,未来的及休眠即被中断的时长

int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *reqtp, struct timespec *remtp);

头文件:#include <time.h>

返回值:成功,返回0;若出错,返回错误码

参数:clock_id:指定了计算延迟时间基于的时钟类型

flags:用于控制延迟是相对的还是绝对的,0:相对的,TIME_ABSTIME:绝对的

req:保存的是,休眠的时间长,

remtp:保存的是,未来的及休眠即被中断的时长

转载地址:http://rgsub.baihongyu.com/

你可能感兴趣的文章
Jmeter之参数化
查看>>
Shell 和Python的区别。
查看>>
Python 列表(list)、字典(dict)、字符串(string)常用基本操作小结
查看>>
Loadrunner之https协议录制回放报错如何解决?(九)
查看>>
python中xrange和range的异同
查看>>
列表、元组、集合、字典
查看>>
【Python】easygui小甲鱼
查看>>
【Python】关于Python多线程的一篇文章转载
查看>>
【Pyton】【小甲鱼】文件
查看>>
【Pyton】【小甲鱼】永久存储:腌制一缸美味的泡菜
查看>>
【Pyton】【小甲鱼】异常处理:你不可能总是对的
查看>>
APP性能测试工具
查看>>
【Pyton】【小甲鱼】类和对象
查看>>
压力测试工具JMeter入门教程
查看>>
作为一名软件测试工程师,需要具备哪些能力
查看>>
【Pyton】【小甲鱼】类和对象:一些相关的BIF(内置函数)
查看>>
【Pyton】【小甲鱼】魔法方法
查看>>
单元测试需要具备的技能和4大阶段的学习
查看>>
【Loadrunner】【浙江移动项目手写代码】代码备份
查看>>
Python几种并发实现方案的性能比较
查看>>