Linux-信号

来源:互联网 发布:2g网络速度 编辑:程序博客网 时间:2024/06/05 01:03

信号

信号概念

信号是为了操作系统能控制进程正确的运行而产生的一种机制。它分为俩种类型,第一种是普通信号(标准信号),第二种是实时信号。通常进程产生普通信号有四种方式:
1 由键盘特殊的组合按键产生,该方式产生的信号发送给一个控制终端的前台作业。
2 由系统调用接口或者命令发出一个信号。(列如kill 命令,abort—异常终止信号)
3 由进程自身错误操作产生的异常导致的信号
4 软件条件产生的信号(列如 alarm , 还有管道中的SIGPIPE)

普通信号(Standard Signals)

Linux下普通信号为1~32。它由pending表/block表/handler表来管理。当有多个非同类型的普通信号产生时,信号抵达顺序是未定义的。有多个同类型的信号产生的时候,pending表只记录一个。还有一个就是Linux下的普通信号都是可靠信号。(这个意思就是多个同种类型信号产生的时候,系统会阻塞该信号,最终产生完毕后,接触阻塞最终只有一个信号产生)

实时信号(Run-time)

实时信号都是未定义的信号,在用户定义之前。它的抵达是有序抵达,以数字小的为最高优先级。当有多个同类型的信号产生时,按顺序抵达。使用应配合宏来一起使用SIGRTMIN+n ,但是不能超过 SIGRTMAX 。它的范围是64-33,刚好32个。使用宏的原因是,Linuxthreads线程库使用了3个实时信号,posix线程库使用了2个。我们用宏编译器会自动转换的。
当实时信号和普通信号同时产生时,Linux以先处理普通信号。

被信号中止的系统调用和库函数

epoll类的系统调用,system v 的系统调用,select poll epoll,已经设置了超时的网络系统调用的函数等系统调用被中止后返回 ENTER 错误。
read, readv, write, writev, ioctl,wait,waitpid等函数被中断后,如果由signal函数注册的自定义函数/sigaction函数设置了 SA_RESTART 标志的话,这些被中断的系统调用会自动重启。

信号的处理方式

信号一般由产生到未决再到递达。产生:系统在该进程pcb的信号字段修改该进程的pending表中相应的有效位。未决:pending表中有未处理的信号,该进程还没有对相应的信号进行处理。递达:已经处理了相应的信号。递达有三种方式,忽略SIG_DFL,默认动作SIG_IGN,自定义handler的一个函数指针。忽略也是递达的一种方式,如果信号被阻塞永远不会被递达。

下图是我另一篇博客中关于task_struct的信号字段的截图

这里写图片描述

进程中保存信号的数据结构

这里写图片描述
信号在pcb中的三个数据结构。
block表:它又称信号屏蔽字,这个表中的有效位表示,即使信号处于未决状态也不能递达,该信号处于屏蔽状态
pending表:它又称未决表,该表记录了进程未处理的信号。它的有效位表示该信号进程已收到但还未处理。
handler表:表示信号的处理方式。

代码验证pending表与block表

#include <stdio.h>#include <signal.h>void handler(int signum){  printf("ctrl-c ----> SIGINT\n");}void printsigset(sigset_t * set){       size_t idx=0;    for(idx=0;idx<32;idx++)    {         if(0==sigismember(set,idx))        putchar('0');       else        putchar('1');    }    putchar('\n');}int main(){  struct sigaction act,oact;  sigset_t mask,oldmask,pending;  act.sa_handler=handler;  act.sa_flags=0;  sigemptyset(&act.sa_mask);  sigemptyset(&mask);  sigemptyset(&oldmask);  sigemptyset(&pending);  sigaddset(&mask,SIGINT);  sigprocmask(SIG_BLOCK,&mask,&oldmask);  sigaction(SIGINT,&act,&oact);  int second=0;   while(second++<5)   {        sigpending(&pending);     printf("pending table:\n");     printsigset(&pending);     sleep(1);      printf("block table:\n");     printsigset(&mask);   }      sigsuspend(&oldmask);    printf("ok.. Now recovered block table\n");   sigprocmask(SIG_SETMASK,&oldmask,NULL);   sigpending(&pending);   printf("Now pending table\n");   printsigset(&pending);   sigaction(SIGINT,&oact,NULL);   return 0;}

这里写图片描述

特殊的三个信号

SIGKILL

不能被阻塞、忽略、捕捉。

SIGSTOP

不能被阻塞、忽略、捕捉。

SIGABRT

不能被阻塞、忽略,但是可以被捕捉,虽然可以捕捉,但是在执行完自定义函数后进程还是会被终止。唯一的区别,如果捕捉,会自动在自定义函数中调用 fclose(NULL)然后关闭所有I/O流的同时刷新I/O流缓冲区。

原创粉丝点击