Linux中关于信号的一些知识
一.什仫是信号?
信号其实是一种软件中断,它为程序提供了一种处理异步时间的方法,而所谓的异步时间就是时间可能会在任何时间内发生,很多重要的程序都需要对信号进行处理。可以使用kill -l查看系统中所有的信号列表以及他们的信号编号。
我们把编号为1~31的信号叫做普通信号,把34~64的信号称作实时信号。所有的信号都包含在头文件signal.h中,且都被定义为正整数常量,也就是他们的信号编号。
二.信号的产生方式?
在Linux下信号一般通过以下几种方式产生:
1).信号来自键盘。用户在终端按下某些键时,终端驱动程序会发送信号给前台进程,但是该信号只能使前台进程终止。比如ctrl+c发送SIGINT信号,ctrl+\发送SIGQUIT信号,ctrl+z发送SIGTSTP信号。
2).软硬件异常。例如除数为0、无效的内存引用对应的SIGSEGV信号,硬件异常产生信号不同,一旦硬件异常产生 ,那么他会一直存在,直到程序被终止位置,所以处理硬件异常信号一般都采用终止程序的方法。
3).经过系统调用向进程发送信号,进程可以通过在shell下运行kill指令来对某个进程发送信号,kill指令是kill系统调用的一个接口。
三.信号的处理方式?
1).忽略此信号。大多数信号都可以采用这种方式进行处理,除了9号信号SIGKILL 和19号信号SIGSTOP 。因为这两种信号都直接向内核提供了进程终止和停止的可靠办法。(SIGKILL),还有硬件异常信号我们最好不要忽略,因为硬件异常一旦产生如果不进行处理就会一直存在。
2).执行默认动作,一般是终止该进程。
3).提供一个信号处理函数,捕捉该信号,属于用户自定义动作。一般使用的是signal函数。
四.阻塞信号?
1.在这里就要提到几个概念:
1).信号递达:实际执行信号的处理动作 。
2).信号未决:pending,表示信号从产生到信号递达的状态。
3).信号阻塞:block,表示信号不能被递达,如果一个信号被阻塞,那么这个信号将会一直处于未决状态,直到解除阻塞为止。
每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上述例子中可以发现:
1). SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
2). SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
3). SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。
#include <signal.h>
int sigemptyset(sigset_t *set); //初始化set所指向的信号集,使set包含所有信号
int sigfillset(sigset_t *set); //初始化set所指向的信号集,使其中所有信号的对
应bit置位,表示该信号集的有效信号包括系统支持的所有信号
int sigaddset(sigset_t *set, int signum); //将一个信号添加到已经存在的信号集中
int sigdelset(sigset_t *set, int signum); //从已有信号集中删除一个信号
int sigismember(const sigset_t *set, int signum); //测试信号集是否包含signum信号
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
sigprocmask:仅为单线程进程进行定义的,在处理多线程时应该使用sigaction函数。
how:指示如何修改当前的信号屏蔽字,可以选择下面三个参数:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void showpending(sigset_t *pending)
{
int i=0;
for(i=1;i<=31;i++)
{
if(sigismember(pending,i))
printf("1 ");
else
printf("0 ");
}
printf("\n");
}
void handler(int sign)
{
printf("pid is %d,sign is %d\n",getpid(),sign);
return;
}
int main()
{
sigset_t sigset,osigset; //定义信号集对象
sigemptyset(&sigset); //清空初始化
sigemptyset(&osigset);
sigaddset(&sigset,SIGINT); //添加2号信号到已经存在的信号集中
sigprocmask(SIG_SETMASK,&sigset,&osigset); //读取或更改信号的信号屏蔽字
signal(2,handler); //对2号信号进行自定义的信号处理操作
int count=0;
sigset_t pending;
while(1)
{
sigpending(&pending); //获取未决信号
showpending(&pending); //打印pending表
sleep(1);
if(count++ > 3)
{
sigprocmask(SIG_SETMASK,&osigset,&sigset); //count秒之后清空pending表
count=0;
}
}
return 0;
}
上一篇: 【Linux】中的进程信号三张表
下一篇: Qt中connect函数(信号与槽)初识