本文地址:http://www.cnblogs.com/archimedes/p/c-library-signal.html,转载请注明源地址。

背景知识

signal.h是C标准函数库中的信号处理部分, 定义了程序执行时如何处理不同的信号。信号用作进程间通信, 报告异常行为(如除零)、用户的一些按键组合(如同时按下Ctrl与C键,产生信号SIGINT)。信号是程序执行过程中发生的异常事件,同步信号的产生是因为程序自身的某些动作,例如除零或不正当的访问存储器,异步信号是由程序外部的行为引起的,比如有人敲击了提示键或者另外一个程序(异步地执行)给你的程序发信号,都会引发一个异步信号。程序不能屏蔽的信号要求立即得到处理。如果不对发生的信号指定一种处理方法,那么它就会被作为一种致命错误对待,然后程序就会以失败的状态终止执行

头文件<singal.h>定义了一个无穷信号集的各种编码值:

  1. #define _NSIG 16 //能够使用的信号的数量
  2.  
  3. #define SIGHUP 1 // 挂起
  4. #define SIGINT 2 // 中断 (DEL)
  5. #define SIGQUIT 3 // 退出 (ASCII FS)
  6. #define SIGILL 4 // 非法指令
  7. #define SIGTRAP 5 // 跟踪中断 (捕捉的时候没有重置)
  8. #define SIGABRT 6 // IOT 指令
  9. #define SIGIOT 6 // 终止使用PDP-11
  10. #define SIGUNUSED 7 // 备用代码
  11. #define SIGFPE 8 // 浮点型异常
  12. #define SIGKILL 9 // kill (不能捕获或忽略)
  13. #define SIGUSR1 10 // 用户定义信号 # 1
  14. #define SIGSEGV 11 // 内存段异常
  15. #define SIGUSR2 12 // 用户定义信号 # 2
  16. #define SIGPIPE 13 // 在管道上写操作没有其他的读操作
  17. #define SIGALRM 14 // 警告
  18. #define SIGTERM 15 // kill后获得软件终止信号
  19.  
  20. #define SIGEMT 7 // 旧式
  21. #define SIGBUS 10 // 旧式
  22.  
  23. /* POSIX 要求定义下面的信号, 即使它们不被支持. 这里给出这些定义, 但是它们不被支持. */
  24. #define SIGCHLD 17 // 子进程终止或停止
  25. #define SIGCONT 18 // 如果停止则继续
  26. #define SIGSTOP 19 // 停止信号
  27. #define SIGTSTP 20 // 交互式停止信号
  28. #define SIGTTIN 21 // 后台进程试图读
  29. #define SIGTTOU 22 // 后台进程试图写

两个函数:

raise函数,报告一个同步信号

  1. int raise (int _sig);

signal函数,可以指定一种信号的处理方法

  1. __sighandler_t signal (int _sig, __sighandler_t _func) ;

可以通过一下三种方式处理信号:

  • 默认处理是终止程序,就像上面所描述的那样

  • 信号忽略是直接把它丢弃

  • 信号处理是把控制权移给一个指定的函数

C标准的内容

头文件 <signal.h>为处理各种各样的信号声明了一个类型和两个函数,并定义了几个宏

定义的类型是:sig_atomic_t

  1. typedef int sig_atomic_t;

该类型是整数类型,声明为这种类型的对象可以作为一个原子实体被访问,即使有异步中断发生的时候也是如此。

定义的宏有: SIG_DFL、SIG_ERR、SIG_IGN

  1. #define SIG_ERR ((__sighandler_t) -1) // 出错返回值
  2. #define SIG_DFL ((__sighandler_t) 0) // 默认信号处理
  3. #define SIG_IGN ((__sighandler_t) 1) // 忽略信号

它们展开为具有不同值的常量表达式,这些表达式的类型和函数signal的第二个参数及返回值的类型兼容,并且它们的值与所有声明的函数的地址都不相等。

指定信号处理

函数signal:

  1. typedef void (*__sighandler_t) (int);
  2. __sighandler_t signal(int _sig, __sighandler_t _func);

或声明成:

  1. void (*signal(int sig, void (*func) (int)))(int);

signal函数通过3种方式来保证接收到的信号编号sig被依次处理,如果func的值是SIG_DFL,那么会使用默认的信号处理方式;如果func的值是SIG_IGN,那么这个信号就会被忽略;否则,func就指向一个函数,当这个信号发生时,就调用这个函数,这样的函数就被称为信号处理程序。

函数raise:

  1. int raise(int sig);

函数raise把信号sig送给正在执行的程序

返回值:执行成功返回0,否则返回非0

<singal.h>的使用

从本质上说,信号处理是不可移植的。只有当必须指定一个已知的操作系统集的信号处理时,才能使用<signal.h>中声明的函数,不用费尽心思把代码变成通用的,这是不可能的

如果对一个信号的默认处理是可行的,那么就选择这种处理方法,使用自己的信号处理程序会降低可移植性并且可能导致程序对信号的误处理增多,如果必须提供某个信号的处理程序,对其进行分类如下:

不可能返回值的信号处理程序,e.g:SIGFPE和SIGABRT

必须返回值的信号处理程序,e.g:SIGINT

不能返回值的信号处理程序最后会调用abort、exit或者longjmp来结束。当然,SIGABRT的处理程序不能调用abort来结束。处理程序不应该调用singal使自己重建。如果程序没有终止,就把剩下的工作给其他的函数。如果信号是异步的,要注意程序所有的输入输出,因为这样的操作也会中断库的执行。

必须返回的信号处理程序用一个return语句结束,如果它想让自己复位,那么应该在入口处立即返回。如果信号是异步的,就在一个sig_atomic_t类型的volatile数据对象中存储一个非零值。不要执行其他任何对正在执行的程序有副作用的动作,例如输入输出和访问其他的数据对象

<singal.h>的实现

下面是一个异步信号处理程序的例子:

  1. #include<signal.h>
  2. static sig_atomic_t intflag = ;
  3. static void field_int(int sig) {
  4. signal(SIGINT, &field_int);
  5. intflag = ;
  6. return;
  7. }

这个程序调用signal(SIGINT, &field_int)来创建处理程序。它会不时地执行下面的代码来检查是否发生了异步交互式提示中断:

  1. if(intflag) {
  2. //执行中断
  3. intflag = ;
  4. ...
  5. }

raise.c

  1. #include<stdio.h>
  2. #include<signal.h>
  3. #include<stdlib.h>
  4. _sigfun *_sigtable[_NSIG] = {};
  5. int raise(int sig)
  6. {
  7. _sigfun *s;
  8. if(sig <= || _NSIG <= sig)
  9. return -;
  10. if((s = _sigtable[sig]) != SIG_IGN && s!= SIG_DFL) {
  11. _sigtable[sig] = SIG_DFL;
  12. (*s)(sig);
  13. } else if (s == SIG_DFL) {
  14. char ac[], *p;
  15. switch(sig) {
  16. case SIGABRT:
  17. p = "abort";
  18. break;
  19. case SIGFPE:
  20. p = "arithmetic error";
  21. break;
  22. case SIGILL:
  23. p = "invalid executable code";
  24. break;
  25. case SIGINT:
  26. p = "interruption";
  27. break;
  28. case SIGSEGV:
  29. p = "invalid storage access";
  30. break;
  31. case SIGTERM:
  32. p = "termination request";
  33. break;
  34. default:
  35. *(p = &ac[sizeof(ac) - ]) = '\0';
  36. do
  37. *--p = sig % + '';
  38. while((sig /= ) != );
  39. fputs("signal #", stderr);
  40. break;
  41. }
  42. fputs(p, strerr);
  43. fputs(" -- terminating\n", stderr);
  44. exit(EXIT_FAILURE);
  45. }
  46. return ;
  47. }

signal.c

  1. #include<signal.h>
  2. _sigfun *_sigtable[_NSIG];
  3. _sigfun *signal(int sig, _sigfun *fun)
  4. {
  5. _sigfun *s;
  6. if(sig <= || _NSIG <= sig || fun == SIG_ERR)
  7. return SIG_ERR;
  8. s = _sigtable[sig];
  9. _sigtable[sig] = fun;
  10. return s;
  11. }

C标准库<signal.h>实现的更多相关文章

  1. C 标准库 - ctype.h

    C 标准库 - ctype.h This header declares a set of functions to classify and transform individual charact ...

  2. C标准库<ctype.h>实现

    本文地址:http://www.cnblogs.com/archimedes/p/c-library-ctype.html,转载请注明源地址. 1.背景知识 ctype.h是C标准函数库中的头文件,定 ...

  3. C 标准库 - ctype.h之iscntrl 使用

    iscntrl int iscntrl ( int c ); Check if character is a control character 检查给定字符是否为控制字符,即编码 0x00-0x1F ...

  4. C 标准库 - ctype.h之isalpha使用

    isalpha int isalpha ( int c ); Checks whether c is an alphabetic letter. 检查给定字符是否字母字符,即是大写字母( ABCDEF ...

  5. C 标准库 - ctype.h之isalnum使用

    isalnum int isalnum ( int c ); Checks whether c is either a decimal digit or an uppercase or lowerca ...

  6. C 标准库 - string.h

    C 标准库 - string.h This header file defines several functions to manipulate C strings and arrays. stri ...

  7. C 标准库 - <assert.h>

    C 标准库 - <assert.h> 简介 C 标准库的 assert.h头文件提供了一个名为 assert 的宏,它可用于验证程序做出的假设,并在假设为假时输出诊断消息. 已定义的宏 a ...

  8. C 标准库 - <stdarg.h>

    C 标准库 - <stdarg.h> 简介 stdarg.h 头文件定义了一个变量类型 va_list 和三个宏,这三个宏可用于在参数个数未知(即参数个数可变)时获取函数中的参数. 可变参 ...

  9. C 标准库 - <signal.h>

    C 标准库 - <signal.h> 简介 signal.h 头文件定义了一个变量类型 sig_atomic_t.两个函数调用和一些宏来处理程序执行期间报告的不同信号. 库变量 下面是头文 ...

  10. C 标准库 - <setjmp.h>

    C 标准库 - <setjmp.h> 简介 setjmp.h 头文件定义了宏 setjmp().函数 longjmp() 和变量类型 jmp_buf,该变量类型会绕过正常的函数调用和返回规 ...

随机推荐

  1. EventKit 学习(译)

    From:http://docs.xamarin.com/guides/ios/platform_features/introduction_to_eventkit/ 本教程展示了对于如何通过Even ...

  2. Android SQLite的ORM接口实现(一)---findAll和find的实现

    最近在看Android的ORM数据库框架LitePal,就想到可以利用原生的SQLite来实现和LitePal类似的ORM接口实现. LitePal有一个接口是这样的: List<Status& ...

  3. React中的PropTypes详解

    propTypes用来规范props必须满足的类型,如果验证不通过将会有warn提示. React PropTypes的种类有: React.PropTypes.array // 队列 React.P ...

  4. stl的优先级队列

    #include <iostream> #include <vector> #include <queue> using namespace std; class ...

  5. ADO.NET基础01

    数据库中数据的导入导出   在使用一些数据库时,很多时候都要将文件导入导出到指定的文件夹中: 数据的导入导出就必须用到stream函数,这就必须用到Using System.IO的命名空间: **在数 ...

  6. [CLR via C#]21. 自动内存管理(垃圾回收机制)

    目录 理解垃圾回收平台的基本工作原理 垃圾回收算法 垃圾回收与调试 使用终结操作来释放本地资源 对托管资源使用终结操作 是什么导致Finalize方法被调用 终结操作揭秘 Dispose模式:强制对象 ...

  7. Python基础:映射(字典)

    一.概述 映射类型(Mapping Types)是一种关联式的容器类型,它存储了对象与对象之间的映射关系. 字典(dict)是Python中唯一的映射类型,它是存储了一个个 键值对(由 键 映射到 值 ...

  8. Foreach能够循环的本质

    我们对foreach循环并不陌生,在C#中我们用得非常多,但是我们是否清楚foreach循环的本质呢? 众所周知,foreach循环能够遍历 数组  ,集合 .但是我们自己定义的一个类是否能够通过fo ...

  9. 重新想象 Windows 8 Store Apps (52) - 绑定: 与 Element Model Indexer Style RelativeSource 绑定, 以及绑定中的数据转换

    [源码下载] 重新想象 Windows 8 Store Apps (52) - 绑定: 与 Element Model Indexer Style RelativeSource 绑定, 以及绑定中的数 ...

  10. csharp: NHibernate and Entity Framework (EF) (object-relational mapper)

    代码生成器: 1. http://www.codesmithtools.com/ 2.https://sourceforge.net/projects/mygeneration/ 3. http:// ...