UNIX系统的信号机制最简单的接口是signal函数。signal函数的功能:为指定的信号安装一个新的信号处理函数。

#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);

复杂原型分开看:

void (* signal( int signo, void (*func)(int) )  )(int);

函数名      :signal

函数参数   :int signo, void (*func)(int)

返回值类型:void (*)(int);

signo参数是信号名(参见:http://www.cnblogs.com/nufangrensheng/p/3514157.html中UNIX系统信号Signal栏下的信号名)。func的值是常量SIG_IGN、常量SIG_DFL或当接到此信号后要调用的函数的地址。如果指定SIG_IGN,则向内核表示忽略此信号(记住有两个信号SIGKILL和SIGSTOP不能忽略)。如果指定SIG_DFL,则表示接到此信号后的动作是系统默认动作。当指定函数地址时,则在信号发生时,调用该函数,我们称这种处理为“捕捉”该信号。称此函数为信号处理程序(signal handler)或信号捕捉函数(signal-catching function)。

signal的返回值是指向之前的信号处理程序的指针。(之前的信号处理程序,也就是在执行signal(signo,func)之前,对信号signo的信号处理程序)

开头所示的signal函数原型太复杂了,如果使用下面的typedef,则可使其简单一些:

typedef void Sigfunc(int);

然后,可将signal函数原型写成:

Sigfunc *signal(int,Sigfunc *);

如果查看系统的头文件<signal.h>,则很可能会找到下列形式的声明:

#define    SIG_ERR        ( void (*) () )-1
#define SIG_DFL ( void (*) () )0
#define SIG_IGN ( void (*) () )1

这些常量可用于代替“指向函数的指针,该函数需要一个整型参数,而且无返回值”。signal的第二个参数及其返回值就可用它们表示。这些常量所使用的三个值不一定是-1,0和1。但大多数UNIX系统都使用上面所示的值。

程序清单10-1 捕捉SIGUSR1和SIGUSR2的简单程序

#include "apue.h"

static void sig_usr(int);    /* one handler for both signals */

int
main(void)
{
if(signal(SIGUSR1, sig_usr) == SIG_ERR)
err_sys("can't catch SIGUSR1");
if(signal(SIGUSR2, sig_usr) == SIG_ERR)
err_sys("can't catch SIGUSR2");
for(;;)
pause();
} static void
sig_usr(int signo) /* argument is signal number */
{
if(signo == SIGUSR1)
printf("received SIGUSR1\n");
else if (signo == SIGUSR2)
printf("received SIGUSR2\n");
else
err_dump("received signal %d\n", signo);
}

pause函数,它使调用进程在接到一个信号前挂起。

我们在后台运行该程序,并且用kill(1)命令将信号传送给它。注意,在UNIX中,杀死(kill)这个术语是不恰当的。kill(1)命令和kill(2)函数只是将一个信号送给一个进程或进程组。信号是否终止进程则取决于信号的类型,以及进程是否安排了捕捉该信号。

因为执行程序清单10-1的进程不捕捉SIGTERM信号,而针对该信号的系统默认动作是终止,所以当该进程发送SIGTERM信号后,该进程就会终止。

1、程序启动

当执行一个程序时,所有信号的状态都是系统默认或忽略。通常所有信号都被设置为它们的默认动作,除非调用exec的进程忽略该信号。确切地讲,exec函数将原先设置为要捕捉的信号都更改为它们的默认动作,其他信号的状态则不变(对于一个进程原先要捕捉的信号,当其执行一个新程序后,就自然不能再捕捉它了,因为信号捕捉函数的地址很可能在所执行的新程序文件中无意义)。

一个具体的例子是一个交互式shell如何处理针对后台进程的中断和退出信号。对于一个非作业控制shell,当在后台执行一个进程时,例如:

cc main.c &

shell自动将后台进程中对中断和退出信号的处理方式设置为忽略。于是,当按中断键时就不会影响到后台进程。如果没有执行这样的处理,那么当按中断键时,它不但会终止前台进程,还会终止所有后台进程。

很多捕捉这两个信号的交互式程序具有下列形式的代码:

void sig_int(int), sig_quit(int);

if(signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, sig_int);
if(signal(SIGQUIT, SIG_IGN) != SIG_IGN)
signal(SIGQUIT, sig_quit);

这样处理后,仅当信号当前未被忽略时,进程才会捕捉它们。

从signal的这两种调用中也可以看到这种函数的限制:不改变信号的处理方式就不能确定信号的当前处理方式

2、进程创建

当一个进程调用fork时,其子进程继承父进程的信号处理方式。因为子进程在开始时复制了父进程的存储映像,所以信号捕捉函数的地址在子进程中是有意义的。

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

信号之signal函数的更多相关文章

  1. [学习笔记]信号基本概念(中断和信号)/名称及常用信号/信号处理/signal函数实践

    1基本概念 中断 q  中断是系统对于异步事件的响应 q  中断信号 q  中断源 q  现场信息 q  中断处理程序 q  中断向量表 异步事件的响应:进程执行代码的过程中可以随时被打断,然后去执行 ...

  2. Linux 信号(二)—— signal 函数

    弗洛伊德认为:要解决这些苦恼,当事人就要通过回忆并理解自己早期的童年经历,来获得对潜意识冲突的顿悟.弗洛伊德的疗法被称为“精神分析” (psychoanalysis),在 20 世纪的很长一段时间被心 ...

  3. Linux 信号详解一(signal函数)

    信号列表 SIGABRT 进程停止运行 SIGALRM 警告钟 SIGFPE 算述运算例外 SIGHUP 系统挂断 SIGILL 非法指令 SIGINT 终端中断 SIGKILL 停止进程(此信号不能 ...

  4. signal函数、sigaction函数及信号集(sigemptyset,sigaddset)操作函数

    信号是与一定的进程相联系的.也就是说,一个进程可以决定在进程中对哪些信号进行什 么样的处理.例如,一个进程可以忽略某些信号而只处理其他一些信号:另外,一个进程还可以选择如何处理信号.总之,这些总与特定 ...

  5. UNIX环境高级编程——信号基本概述和signal函数

    一.为了理解信号,先从我们最熟悉的场景说起:1. 用户输入命令,在Shell下启动一个前台进程.2. 用户按下Ctrl-C,这个键盘输入产生一个硬件中断.3. 如果CPU当前正在执行这个进程的代码,则 ...

  6. POSIX信号和自定义signal函数

    一.信号的概念 信号(signal)就是告知某个进程发生了某个事件的通知:信号通常是异步发生的,也就是说接受信号的进程不知道信号的准确 发生时刻:信号可以(1)由一个进程发给另一个进程:(2)由内核发 ...

  7. 三十、Linux 进程与信号——信号的概念及 signal 函数

    30.1 信号的基本概念 信号(signal)机制是Linux 系统中最为古老的进程之间的通信机制,解决进程在正常运行过程中被中断的问题,导致进程的处理流程会发生变化 信号是软件中断 信号是异步事件 ...

  8. UNIX高级环境编程(13)信号 - 概念、signal函数、可重入函数

    信号就是软中断. 信号提供了异步处理事件的一种方式.例如,用户在终端按下结束进程键,使一个进程提前终止.   1 信号的概念 每一个信号都有一个名字,它们的名字都以SIG打头.例如,每当进程调用了ab ...

  9. Linux下利用signal函数处理ctrl+c等信号

    前言 linux下能够通过信号机制来实现程序的软中断,是一个很实用的编程方法. 我们平时在程序执行的时候按下ctrl-c.ctrl-z或者kill一个进程的时候事实上都等效于向这个进程发送了一个特定信 ...

随机推荐

  1. 一排下去再上来的div

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  2. SharePoint咨询师之路:设计之前的那些事四:负载均衡 - web服务器

     提示:本系列只是一个学习笔记系列,大部分内容都可以从微软官方网站找到,本人只是按照自己的学习路径来学习和呈现这些知识.有些内容是自己的经验和积累,如果有不当之处,请指正. 容量管理 规模 体系结构 ...

  3. http://blogs.msdn.com/b/pranavwagh/archive/2007/03/03/word-2007-file-seems-to-be-deleted-when-you-open-and-save-it-using-dsoframer.aspx

    http://blogs.msdn.com/b/pranavwagh/archive/2007/03/03/word-2007-file-seems-to-be-deleted-when-you-op ...

  4. MSSQL手札三 MSSQL存储过程

    --存储过程完成一段sql代码的封装 create proc trim --参数列表,多个间用逗号分隔 ) as --自定义代码段 ) set @str1=LTRIM(RTRIM(@str)) pri ...

  5. uestc oj 1217 The Battle of Chibi (dp + 离散化 + 树状数组)

    题目链接:http://acm.uestc.edu.cn/#/problem/show/1217 给你一个长为n的数组,问你有多少个长度严格为m的上升子序列. dp[i][j]表示以a[i]结尾长为j ...

  6. hdoj 5399 Tpp simple

    WA了一下午.... 1WA:T了,因为阶乘没打表所以时间超了.. 2WA,3WA:runtime error,检查的value数组开小了,应该是MAXN.. 4WA.5WA.6WA:改了改对cnt的 ...

  7. Linux下如何用vi编辑和保存文件

    vi是Linux终端下或控制台下常用的编辑器,基本的操作方式为:vi /路径/文件名 例如,vi /etc/fstab表示显示/etc/fstab文件的内容.使用键盘上的Page Up和Page Do ...

  8. C# WinForm开发系列 - RDLC

    http://www.cnblogs.com/peterzb/archive/2009/07/08/1519489.html http://jingyan.baidu.com/article/ab69 ...

  9. 【css hack】正是我所找的,帮了大忙啊

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期2014-03-05) 各个浏览器单独设置属性 IE6:能识别下划线 “_” 和 星号 “*“,不能识别 “!important”    ...

  10. arm_cm4.c关于kinetis的修改

    /***********************************************************************/ /* * Initialize the NVIC t ...