Linux下信号的基本使用与分析

1.基本概念

信号是事件发生时对进程的通知机制,一个进程可以想另一个进程发送信号,此做法可以实现进程间的同步,然而给进程发信号的通常都是内核

(1)内核一般都会在发生以下事件时给进程发信号 .硬件发生异常 .用户键入了能够产生信号的终端特殊字符 .发生了软件事件 针对每一个信号,都定义了一个唯一的整数

(2)如果内核要调度该进程,等待信号就会马上送达,然而有时进程不想中断代码,进程可以将该信号添加到进程的信号掩码中,此信号将处于等待状态,知道进程将其从信号掩码中解除出来

(3)信号到达后,进程根据具体信号执行如下操作 .忽略信号:内核将信号丢弃,信号对进程不产生影响终止进程:进程异常终止 .停止进程:暂停进程的执行

具体的信号都是由信号处理函数来执行的

2.信号类型和默认行为

信号名称 描述

SIGABRT 终止进程

SIGALRM 实时定时器过期

SIGBUS 内存访问出错

SIGCHLD 终止子进程

SIGCONT 若停止则继续

SIGEMT 硬件错误

SIGFPE 算数异常

SIGHUP 刮起

SIGTLL 非法指令

SIGINT 终端中断

SIGIO I/0时可能产生

SIGKILL 必杀

SIGPIPE 管道断裂

SIGPROF 性能分析定时器过时

SIGQUIT 终端退出

SIGSEGV 无效的内存访问

SIGSTKFLT 协议处理栈错误

SIGSTOP 确保停止

SIGSYS 无效的系统调用

SIGUSR 用户自定义信号

3.自定义信号处理函数signal()#include<signal.h>sighandler_t signal(int sig,sighandler_t handler);

第一个参数sig,标注希望修改的信号编号,第二个参数handler,则指明信号到达时,所调用的处理函数,,singal的返回值为之前改信号的处理函数 特别注意:我们可以用SIG_IGN来取代handler参数,它的作用是忽略该信号,如果信号专为此进程而生,则内核会丢弃此信号

4.信号处理器

信号处理器程序(信号捕捉器)是指当指定信号传递给进程时会调用一个函数 调用信号处理器程序会打断主程序流程,内核代表进程来处理程序,当处理完之后,主程序会从打断的位置恢复执行

具体实例sigHanler(int sig){printf(“hello,world\n”);}int main(){int i;if(signal(SIGINT,sigHanler) == SIG_ERR){printf(“error\n”);}for(i=0;i<3;i++){printf(“haha\n”);sleep(2);}}

运行结果如下:

5.发送信号:kill()#include<signal.h>int kill(pid_t,int sig);//成功返回0,失败-1

该调用将会杀掉指定pid的进程,sig则指定了要发送的信号 .如果pid大于0,那么信号发给pid指定的进程 .pid等于0发给同组的每个进程 .pid小于-1,发送给pid绝对值下属的所有进程 .pid等于-1,调用进程有权将信号发给每个进程

6.用kill()检查进程的存在

若将sig参数置为0,则无信号发送,相反kill()仅回去执行错误检查,查看是否可以向进程发送信号。这意味着,可以用其来检查一个进程是否存在,若调用成功那么进程存在。但是这并不能保证该pid的进程就一定存在,有可能该pid指的进程已不是先前的那个进程了

判断进程存在与否的其他方法: (1)wait()系统调运:监控子进程是否存在 (2)信号量和文件锁:如果进程持有这些,那么如果不能取得这些,就以为这进程存在 (3)/proc/PID接口:如果进程存在,目录proc/12345将存在

7.显示信号描述#include<signal.h>char *strsignal(int sig);//返回可打印字符串8.信号集

当系统调用需要一组不同的信号时,就用到了信号集,信号集的数据结构为sigset_t (1)信号集的初始化

#include<signal.h>int sigemptyset(sigset_t *set);

(2)向set中添加或删除单个信号

#include<signal.h>int sigaddset(sigset_t *set,int sig);int sigdelset(sigset_t *set,int sig);

(3)判断sig是否在set中

#include<signal.h>int sigismember(const sigset_t *set,int sig);9.信号掩码

内核会为每个进程维护一个信号掩码,即一组信号,并将阻塞其对进程的传递。如果将遭阻塞的信号发送给进程,对该信号的传递将延后,直至从信号掩码中移除该信号

sigprocmask系统调用:

#include<signal.h>int sigprocmask(int how,const sigset_t *set,sigset_t *oldset);

sigprocmask()调运即可修改进程的信号掩码,又可获取现有掩码,或者俩重功效兼具,how参数指定给信号掩码带来的变化

how参数 具体描述

SIG_BLOCK 将set指向信号集中的指定信号添加到信号掩码中

SIG_UNBLOCK 将set指向信号集中的信号从信号掩码中删除

SIG_SETMASK 将set指向的信号集赋给信号掩码

10.等待状态的信号以及排队

若进程接收了一个正在阻塞的信号,则它会将该信号添加到进程的等待信号集中,不管该信号被发了多少此,在该信号被解除阻塞时,都只会给进程传递一次

11.改变信号处置:sigaction()sigaction *act,struct sigaction *oldact);

.sig参数标识想要获取或改变的信号编号 .act参数是指针,指向描述信号新处置的数据结构 .oldact参数用来返回之前信号处置的相关信息,若不想获取设为NULL sigaction结构定义如下

struct sigaction{void (*sa_handle)(int);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);//不给应用程序使用}

其中sa_flags字段是一个位掩码,指定用于控制信号处理过程的各种选项(可以相或)

sa_flag字段 具体描述

SA_NOCLDSTOP 若sig为SIGCHLD(终止子进程),则恢复或停止子进程时,将不再产生此信号

SA_NOCLDWAIT 若sig为SIGCHLD信号,则当子进程终止时,不会将其转换为僵尸

SA_NODEFEP 捕获该信号时,不会在执行处理器程序时将该信号自动添加到进程掩码中

SA_ONSTACK 针对此信号调用处理器函数时,使用了由sigaltstack()安装俄被选栈

SA_RESTART 自动重启由信号处理器程序中断的系统调用

12.pause()#include<unistd.h>int pause(void)

调用pause()函数将暂停进程的执行,直至信号处理函数中断该调用为止

走自己的路,让人家去说吧。

Linux下信号的基本使用与分析

相关文章:

你感兴趣的文章:

标签云: