参考博客:http://blog.csdn.net/alex_my/article/details/39494129

1. 信号概念

何为信号?

信号是一种软中断,可以由以下情形触发:

-1: 用户按下某些终断键,例如ctrl + C ,这可以停止一个失去控制的程序。(ctrl + D并不是发送信号,而是抛出一个

EOF 结束符,使程序退出。)

-2: 硬件异常,例如除数为0,无效的内存引用

-3:kill(2), kill(1) (接收信号的进程必须与发送信号进程的所有者相同,或者发送信号进程的uid为root)

-4: 当软件条件达成,且有进程需要得到此通知

注:信号是异步事件的经典实例。

当信号发生时,可以告诉内核进行以下处理:

-1:忽略信号(SIG_IGN): 有两个信号不能被忽略,SIGKILL(9), SIGSTOP(19), 不能被忽略的原因是这两个信号为内核和超级用户提供了一条可靠的方法去杀死和暂停进程。当忽略一些来自硬件的异常信号,产生的结果是未定义的,不如引用了无效的内存,除数为0。

-2:抓取信号: 在抓取信号之前,首先要定义抓取信号之后要如何处理,SIGKILL和SIGSTOP信号不能被捕捉。

-3:默认处理信号(SIG_DEF): 每一个信号都有一个默认的处理,大部分处理方式都是终止进程。如果想看各个的处理方式,可以在终端上输入man 7 signal,以下列出备查。红色标注为常用信号。

Signal     Value     Action   Comment

------------------------------------------------------------------------------------------------------------------------------------------------

SIGHUP        1        Term    Hangup detected on controlling terminal

or death of controlling process

SIGINT          2        Term      Interrupt from keyboard

SIGQUIT       3        Core    Quit from keyboard

SIGILL           4        Core    Illegal Instruction

SIGABRT      6        Core    Abort signal from abort(3)

SIGFPE         8        Core    Floating point exception

SIGKILL         9        Term    Kill signal

SIGSEGV      11       Core    Invalid memory reference

SIGPIPE        13       Term    Broken pipe: write to pipe with no

readers

SIGALRM      14         Term    Timer signal from alarm(2)

SIGTERM      15         Term    Termination signal

SIGUSR1   30,10,16    Term    User-defined signal 1

SIGUSR2   31,12,17    Term    User-defined signal 2

SIGCHLD   20,17,18    Ign     Child stopped or terminated

SIGCONT   19,18,25    Cont    Continue if stopped

SIGSTOP   17,19,23     Stop    Stop process

SIGTSTP   18,20,24     Stop    Stop typed at terminal

SIGTTIN   21,21,26       Stop    Terminal input for background process

SIGTTOU   22,22,27    Stop    Terminal output for background process

Next the signals not in the POSIX.1-1990 standard but described in SUSv2 and POSIX.1-2001.

SIGBUS      10,7,10     Core    Bus error (bad memory access)

SIGPOLL                     Term    Pollable event (Sys V).

Synonym for SIGIO

SIGPROF     27,27,29    Term    Profiling timer expired

SIGSYS      12,31,12    Core    Bad argument to routine (SVr4)

SIGTRAP        5        Core    Trace/breakpoint trap

SIGURG      16,23,21    Ign     Urgent condition on socket (4.2BSD)

SIGVTALRM   26,26,28    Term    Virtual alarm clock (4.2BSD)

SIGXCPU     24,24,30    Core    CPU time limit exceeded (4.2BSD)

SIGXFSZ     25,25,31    Core    File size limit exceeded (4.2BSD)

Up to and including Linux 2.2, the default behavior for SIGSYS, SIGXCPU, SIGXFSZ, and  (on  architec-
tures other than SPARC and MIPS) SIGBUS was to terminate the process (without a core dump).  (On some
 other Unix systems the default action for SIGXCPU and SIGXFSZ is to terminate the process  without  a
 core  dump.)   Linux 2.4 conforms to the POSIX.1-2001 requirements for these signals, terminating the
process with a core dump.

Next various other signals.

SIGIOT         6        Core    IOT trap. A synonym for SIGABRT

SIGEMT       7,-,7      Term

SIGSTKFLT    -,16,-     Term    Stack fault on coprocessor (unused)

SIGIO       23,29,22    Term    I/O now possible (4.2BSD)

SIGCLD       -,-,18     Ign     A synonym for SIGCHLD

SIGPWR      29,30,19    Term    Power failure (System V)

SIGINFO      29,-,-             A synonym for SIGPWR

SIGLOST      -,-,-      Term    File lock lost (unused)

SIGWINCH    28,28,20    Ign     Window resize signal (4.3BSD, Sun)

SIGUNUSED    -,31,-     Core    Synonymous with SIGSYS

2. signal 函数

#include <signal.h>

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

若出错,返回SIG_ERR

这个signal函数接受两个参数

参数1: 信号名,如SIGCHLD

参数2: 接受信号处理函数指针,函数原型void func(int),也可以是常量SIG_IGN或SIG_DEF

另外,还有三个定义:

#define SIG_ERR (void(*)())-1    // 返回错误值

#define SIG_DFL (void(*)())0      //恢复为参数1所指信号的处理方法为默认方法

#define SIG_IGN (void(*)())1      //
忽略参数1所指信号

可以作为参数2或者signal的返回值

程序用例:

<span style="font-size:14px;">#include "apue.h"

static void sig_func(int signo)

{

     printf("\nsigno: %d\n", signo);

     exit(EXIT_SUCCESS);

}

int main(int argc, char** argv)

{

     if(signal(SIGINT, sig_func) == SIG_ERR)

     {

          printf("signal failed. errno[%d]\t %s\n", errno, strerror(errno));

          exit(EXIT_FAILURE);

     }

     pause();

     exit(EXIT_SUCCESS);

}</span>

输出:

在键盘上按下ctrl + c,产生中断信号。

^C

signo: 2

注意点:

-1:当执行一个程序时,所有信号的状态都是系统默认或者忽略,且信号响应后执行默认动作,直到在程序中做出改变。如同上一程序用例当中,按下ctrl + c后,默认是终止进程,当在程序中做出改变之后,变成执行函数sig_func了。

-2:当使用fork后,子进程继承父进程的信号处理方式。

-3:当fork后又使用exec后,新的程序中的信号又恢复了默认,因为替换旧的数据空间,堆栈等,使得原来处理函数对于新的程序来说,已经失效

-4:对于一个正在执行任务的进程,如果异步捕获了一个信号,并且进入相应的信号处理函数,当它处理完这个函数并想要回到进程中时,可能会使进程“忘记”刚才做到哪里了,这就引入了可重入函数的概念。书中列出了异步信号安全的函数。

一个具体的例子:

假如主线程用malloc申请一个动态空间,并向其中写数据,这是异步获得一个SIG,并跳进SIG处理函数,这个处理函数可能也会向此动态空间写入数据,从而导致破坏了malloc的数据结构。

因此,要避免在信号处理程序中调用非可重入函数。

-5:不可靠的信号是指不具备阻塞信号能力的信号(早起Unix版本中存在的问题)

3.信号集:signal sets

#include <signal.h>

int sigemptyset(sigset_t* set);

int sigfillset(sigset_t* set);

int sigaddset(sigset_t* set, int signum);

int sigdelset(sigset_t* set, int signum);

return 0 on success and -1 on error

int sigismember(const sigset_t* set, int signum);

return 1 if is signum is a member of set, return 0 if not, -1 on error

以上函数可以从字面意思理解:

sigemptyset: (初始化)将set信号集清空

sigfillset : (初始化)将所有的信号填充到set中

sigaddset  : 添加指定信号signum到set中

sigdelset  : 从set中移除指定信号signum

sigismember: 特使signum是否是set中的成员

4. sigprocmask

#include <signal.h>

int pthread_sigmask(int how, const sigset_t* restrict set, sigset_t* restrict oset);

int sigprocmask(int how, const sigset_t* restrict set, sigset_t* restrict oset);

sigprocmask: 用于设定信号屏蔽集内信号的处理方式

参数how可选值如下:

SIG_BLOCK  : set中包含了我们所希望添加的阻塞信号

SIG_UNBLOCK: set中包含了我们所希望解除阻塞的信号

SIG_SETMASK: set中为所设置屏蔽的信号

程序用例:

<span style="font-size:14px;">#include "apue.h"

int main(int argc, char** argv)

{

     sigset_t set;

     sigemptyset(&set);

     sigaddset(&set, SIGINT);

     if(sigismember(&set, SIGINT) == 1)

          printf("SIGINT is a member now\n");

     else

          printf("SIGINT is not a member or error occur\n");

     sigdelset(&set, SIGINT);

     if(sigismember(&set, SIGINT) == 0)

          printf("SIGINT is not a member now\n");

     else

          printf("SIGINT is still a member or error occur\n");

     sigaddset(&set, SIGINT);

     sigprocmask(SIG_SETMASK, &set, NULL);

     getchar();

     // try ctrl + c

     return 0;

}</span>

编译运行之后,可以ctrl + c,可以发现无效。

如果将sigprocmask(SIG_SETMASK, &set, NULL)注释,则可以了。

5. sigpending

#include <signal.h>

int sigpending(sigset_t* set);

return 0 if success and -1 on error.

sigpending: 通过set返回已经通知进程,但被阻塞而挂起的信号(未决信号)。比如阻塞了SIGINT信号一段时间,而在这段时间中产生了这个信号,通知进程,这个信号称之为pending信号。如果产生多个SIGINT信号,在Linux实现中,也只会处理一次。可以通过程序用例观察到。

程序用例:

<span style="font-size:14px;">#include "apue.h"

static void sigfunc(int signo)
{
printf("signo: %d\n", signo);
} int main(int argc, char** argv)
{
sigset_t set, oset, pset; if(signal(SIGINT, sigfunc) == SIG_ERR)
{
printf("signal failed, error[%d]: %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
} sigemptyset(&set);
sigaddset(&set, SIGINT);
if(sigprocmask(SIG_BLOCK, &set, &oset) == -1)
{
printf("sigprocmask failed, error[%d]: %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
//此时,阻塞掉信号集内的信号
// 在此期ctrl + c,可以多次输入,看会处理几次
sleep(5); //处理未决信号,把未决信号SIGINT放入pset信号集
if(sigpending(&pset) == -1)
{
printf("sigpending failed, error[%d]: %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
} if(sigismember(&pset, SIGINT) == 1)
printf("SIGINT is pending\n");
else
printf("SIGINT is not pending\n"); // 不再屏蔽,也可以用SIG_UNBLOCK
if(sigprocmask(SIG_SETMASK, &oset, NULL) == -1)
{
printf("sigprocmask failed2, error[%d]: %s \n", errno, strerror(errno));
exit(EXIT_FAILURE);
} printf("sleep again\n");
// ctrl + c, 可以多次输入,看会处理几次
sleep(5); exit(EXIT_SUCCESS);
}</span>

输出:

第一次sleep时,可以多次输入ctrl + c,5秒结束之后,会显示"SIGINT is pending",且函数sigfunc仅会被调用一次,说明多次输入,在当前的Linux实现中只会被调用一次。

第二次sleep期间,由于SIGINT不再被阻塞,因此输入ctrl + c后,会立即响应。

6. sigaction

#include <signal.h>

int sigaction(int sig, const struct sigaction* restrict act, struct sigaction* restrict oact);

sigaction: 指定或者修改与指定信号相关联的处理动作。可用sigaction实现signal

struct sigaction:{

void    (*sa_handler )(int);                         /*addr of signal handler,

or  SIG_IGN or SIG_DFL.*/

sigset_t   sa_mask                               /*additional signals to block */

int     sa_flags                          /* Special flags to affect behavior of signal. */

void(*sa_sigaction )(int, siginfo_t *, void *)             Pointer to a signal-catching function.

sa_handler: 信号处理函数,参数为int,如同signal函数的参数意愿。

sa_sigaction: 信号处理函数,参数有3个。

至于选择sa_handler指向的函数还是sa_sigaction指向的函数,需要依靠sa_flags判断。

sa_flags: 指定信号处理行为,以下值可以使用或组合

SA_NOCLDSTOP: 父进程在子进程暂停或者继续运行时不会收到SIGCHLD信号

SA_ONSTACK  : 如果设置此标志,且使用了sigaltstack设置了备用信号堆栈,则信号会传递给该堆栈中的进程,否则,在当前的进程中

SA_RESETHAND: 信号处理之后,重新设置为默认的处理方式

SA_RESTART   : 被信号打断的系统调用自动重新发起

SA_SIGINFO  : 使用sa_sigaction做为处理函数,而不是sa_handler

SA_NOCLDWAIT: 父进程在子进程中退出不会收到SIGCHLD信号,且子进程不会变成僵尸进程

SA_NODEFER  : 使sa_mask设置的屏蔽无效

sa_mask: 在信号处理函数执行过程中,屏蔽哪些信号。注意的是,这个屏蔽仅在信号处理函数执行过程中有效,而不是整个进程。

程序用例:

#include "apue.h"

static void sigfunc(int signo)
{
printf("signo: %d\n", signo);
sleep(10);
printf("sleep over\n");
} static void sigfunc_int(int signo)
{
printf("SIGINT occur\n");
} int main(int argc, char** argv)
{
struct sigaction act;
act.sa_flags = SA_NODEFER; sigemptyset(&act.sa_mask); act.sa_handler = sigfunc_int;
sigaction(SIGINT, &act, NULL); act.sa_handler = sigfunc;
sigaddset(&act.sa_mask, SIGINT); /*阻塞SIGINT信号,在输出时,如果我们先用ctrl+c产生SIGINT信号,
则立即处理该信号退出程序,但是如果程序先捕获到的是SIGQUIT信号,
则sigaddset处理会将SIGINT阻塞,先执行sigfunc()函数,sleep10秒后,
执行sigfunc_int函数,完成后退出。
*/
if(sigaction(SIGQUIT, &act, NULL) == -1)
{
printf("sigaction failed");
exit(EXIT_FAILURE);
} sleep(20); printf("\n");
return 0;
}

Unix环境高级编程---信号的更多相关文章

  1. UNIX环境高级编程——信号说明列表

    $ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGK ...

  2. UNIX环境高级编程——信号

    一.信号生命周期 从信号发送到信号处理函数的执行完毕. 对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个重要的阶段,这三个阶段由四个重要事件来刻画:信号诞生:信号在进 ...

  3. UNIX环境高级编程——信号(API)

    一.信号在内核中的表示     实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending).进程可以选择阻塞(Block)某个信号.被阻塞的信号 ...

  4. UNIX环境高级编程——信号之kill、raise、killpg、alarm、pause、abort、sleep、usleep、nanosleep和setitimer函数

    一.kill, raise, killpg 函数 int kill(pid_t pid, int sig); int raise(int sig); int killpg(int pgrp, int ...

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

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

  6. UNIX环境高级编程——sigqueue、sigsuspend函数

    一.sigqueue函数 功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用. int sigqueue(pid_t pid, int sig, ...

  7. (八) 一起学 Unix 环境高级编程 (APUE) 之 信号

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  8. (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  9. (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

随机推荐

  1. hdu 3061 hdu 3996 最大权闭合图 最后一斩

    hdu 3061 Battle :一看就是明显的最大权闭合图了,水提......SB题也不说边数多少....因为开始时候数组开小了,WA....后来一气之下,开到100W,A了.. hdu3996. ...

  2. LeetCode OJ-- Count and Say

    https://oj.leetcode.com/problems/count-and-say/ 求经过n次变换后,变成了什么. 1  11  21  1211   111221 ps. 3 变成 ‘3 ...

  3. Selenium 2.0自动化测试

    http://blog.sina.com.cn/s/blog_b6142fb401017oo6.html http://www.cnblogs.com/halia/p/3562132.html?utm ...

  4. 语义分割丨PSPNet源码解析「训练阶段」

    引言 之前一段时间在参与语义分割的项目,最近有时间了,正好把这段时间的所学总结一下. 在代码上,语义分割的框架会比目标检测简单很多,但其中也涉及了很多细节.在这篇文章中,我以PSPNet为例,解读一下 ...

  5. 注意这几点,轻轻松松配置 Nginx + Tomcat 的集群和负载均衡

    Tomcat 集群是当单台服务器达到性能瓶颈,通过横向扩展的方式提高整体系统性能的有效手段.Nginx 是一个高性能的 HTTP 和反向代理 web 服务器,可以通过简单的配置实现 Tomcat 集群 ...

  6. 2016北京集训测试赛(十一)Problem C: 树链问题

    Solution 智障暴力题, 每个点维护一下子树信息, 树剖就好了. 我居然还傻了写了一发毛毛虫... #include <cstdio> #include <cctype> ...

  7. https://www.cnblogs.com/netoxi/p/7258895.html

    https://www.cnblogs.com/netoxi/p/7258895.html 应用服务和数据服务分离 需求/解决问题 随着网站业务的发展,越来越多的用户访问导致性能越来越差,越来越多的数 ...

  8. nginx 配置静态目录 访问bootstrap

    location /static/ { alias /Users/wangziqiang/djangoprojects/bpmTest/static/; } 注意  /static/   中 /的完整 ...

  9. mysql赋给用户权限grant all privileges on

    查看mysql用户表的结构,Field项都是各类权限限制 Host限制登录的IP,User限制登录的用户,Delete_priv限制删除权限,Grant_priv限制权限授予,Super_priv为超 ...

  10. 怎样备份Github博客至GitCafe

    原文链接:http://stackvoid.com/how-to-transfer-github-pages-to-gitcafe/ 开通博客半年多了,一直将博客托管到 Github 上,使用 Git ...