信号的捕捉和处理

主要由signal和sigaction函数来完成。还有一个函数pause,它可用来响应任何信号,不过不做任何处理。

1、signal函数

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

当指定的信号到达时,就会跳转到参数handler指定的函数执行。如果handler参数不是函数指针,那么必须是常数:

SIG_IGN(忽略该信号)或SIG_DFL(对该信号执行默认操作)。handler是一个函数指针。

signal函数执行成功时返回以前的信号处理函数指针,当有错误发生时返回SIG_ERR(即 -1)

注意:SIGKILL 和 SIGSTOP这两个信号不能被捕捉或忽略。

2、sigaction函数:

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};

用来检查或设置进程在收到信号时的动作。

参数signum可以是SIGKILL 和 SIGSTOP以外的任何信号。

如果参数act不为空,则为signum设置新的信号处理函数;

如果oldact不为空,则旧的信号处理函数将被存储在oldact中。

sa_handler和sa_sigaction在某些体系结构上被定义为共同体,即这两个值在某一时刻只有一个有效。

数据成员sa_restorer已经作废,不再使用,POSIX标准也不支持该数据成员。

sa_handler可以是常数SIG_DFL 或 SIG_IGN,或者是一个信号处理函数的函数名。

sa_sigaction也是用来指定信号signum的处理函数,但是它有3个参数,

第一个参数是信号编号,

第二个参数是一个指向siginfo_t 结构的指针,

第三个参数是一个指向任何类型的指针,一般不使用。

sa_mask成员变量声明了一个信号集,在调用信号捕捉函数之前,该信号集会增加到进程的信号屏蔽码中,新的信号屏蔽码会自动包括正在处理的信号(sa_flags

未指定SA_NODEFER 或 SA_NOMASK)。

当从信号捕捉函数返回时,进程的信号屏蔽码会恢复原来的值。因此,当处理一个给定的信号时,如果这种信号再次发生,那么会阻塞直到本次信号处理

结束为止。若这种信号发生了多次,则对于不可靠信号,他只会阻塞一次,即本次信号处理结束以后只会再处理一次(相当于丢失了信号);对于可靠信号(实时信号),则会被阻塞多次,即

信号不会丢失,信号发送了多少次就会调用信号处理函数多少次。

sa_flags成员用来说明信号处理的一些其他相关操作,它可以取以下或他们的组合。

******

*****

******

SA_SIGINFO:如果设置了该标志,则信号处理函数由三参数的sa_sigaction指定而不是sa_handler指定。

使用三参数的sa_sigaction来指定信号处理函数时,它的第二个参数可以用来传递数据,定义如下:

接收信号的进程只能读取这些值,不能进行设置。si_int,si_ptr可以用来接收数据。

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

信号的嵌套处理:

将sa_flags赋值为SA_NOMASK,即支持信号的嵌套处理。

#include <stdio.h>
#include <signal.h> int temp = ; void sig_handler(int sig_num); int main()
{
struct sigaction act; act.sa_handler = sig_handler;
act.sa_flags = SA_NOMASK; sigaction(SIGINT, &act, NULL); while(); return ;
} void sig_handler(int sig_num)
{
printf("recv SIGINT\n");
sleep();
temp+=;
printf("the value temp is:%d\n", temp);
printf("int sig_handler, after sleep\n"); }

快速按下Ctrl+c组合键两次。

执行说明:

第一次按下Ctrl+c组合键发出SIGINT信号,休眠5秒。在5秒之内再次按下Ctrl+c组合键,由于我们设置了

act.sa_flags = SA_NOMASK;

因此程序又一次响应SIGINT信号,程序从sleep()处嵌套调用信号处理函数void sig_handler(int sig_num);再一次打印

recv SIGINT 。休眠5秒之后,将temp的值打印出来并返回到本次信号处理函数的跳入点sleep处,然后再打印temp的值,并返回到主函数。

从程序执行可以看到,temp的值随着信号处理函数被调用的次数的增加而递增,而由于实际应用中信号总是随机发生的,这样temp的值也会随机变化,

如果main函数或其他地方还用到了这个全局变量,则程序将产生不可预料的结果。我们称这种数据会被破坏的函数为不可重入函数。

编写信号处理函数时要注意不要使用不可重入函数。一般来说,满足下列条件之一的函数是不可重入的。

(1)使用了静态的数据结构,如getgrgid(),全局变量等

(2)函数实现时,调用了malloc或者free函数

(3)函数实现时,调用了标准I/O函数

3、pause函数:

int pause(void);

使调用进程挂起直至捕捉到一个信号。

pause函数会令目前的进程进入睡眠状态,直到被信号所中断。该函数只返回-1并将errno设置为EINTR。

信号处理signal、sigaction、pause、信号嵌套处理、不可重入函数的更多相关文章

  1. 重读APUE(11)-信号安全的可重入函数

    重入时间点 进程捕捉到信号并对其进行处理时,进程正在执行的正常指令序列就会被信号处理程序临时中断,它首先执行该信号粗合理程序中的指令:如果从信号处理程序返回,则继续执行捕捉到信号时进程正在执行的正常指 ...

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

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

  3. Use Reentrant Functions for Safer Signal Handling(译:使用可重入函数进行更安全的信号处理)

    Use Reentrant Functions for Safer Signal Handling 使用可重入函数进行更安全的信号处理 How and when to employ reentranc ...

  4. linux系统编程之信号(四):alarm和可重入函数

    一,alarm() 在将可重入函数之前我们先来了解下alarm()函数使用: #include <unistd.h> unsigned int alarm(unsigned int sec ...

  5. linux可重入、异步信号安全和线程安全

    一 可重入函数 当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断.它首先执行该信号处理程序中的指令.如果从信号处理程序返回(例如没有调用exit或longjmp ...

  6. 三十三、Linux 进程与信号——中断系统调用和函数可重入性

    33.1 中断系统调用 进程调用 “慢” 系统调用时,如果发生了信号,内核会重启系统调用. 慢系统调用 可能会永久阻塞的系统调用 从终端设备.管道或网络设备上的文件读取 向上述文件写入 某些设备上的文 ...

  7. 【C/C++】对于可重入、线程安全、异步信号安全几个概念的理解

    由于前段时间,程序偶尔异常挂起不工作,检查后发现时死锁了,原因就是:在信号处理函数里面调用了fprintf. printf等io函数是需要对输出缓冲区加锁,这类函数对本身是线程安全的,但是对信号处理函 ...

  8. signal, sigaction,信号集合操作

    信号是与一定的进程相联系的,而建立其信号和进程的对应关系,这就是信号的安装登记. Linux主要有两个函数实现信号的安装登记:signal和sigaction.其中signal在系统调用的基础上实现, ...

  9. signal,blinker:信号(看我脸色行事)

    signal 什么是信号(signal)? 信号在linux中被用来进行进程间的通信和异步处理,简单地可以理解会为回调函数,当发送一个信号时,会触发相应的操作.python中的signal模块便是用来 ...

随机推荐

  1. 20165310 java_blog_week3

    2165310 <Java程序设计>第3周学习总结 教材学习内容总结 类 声明与命名规则 驼峰原则 变量:体现属性 方法:体现行为/功能 变量: 成员变量与局部变量: 成员变量:有效范围: ...

  2. noip 2012 提高组 day2 部分题解

    这道题有多种解法,我用的是扩展欧几里得算法求到的答案 #include<iostream> #include<fstream> #include<cstdio> u ...

  3. 常用模块之 time,datetime,random,os,sys

    time与datetime模块 先认识几个python中关于时间的名词: 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量.我们运行“ty ...

  4. JMeter -- Getting Started

    https://jmeter.apache.org/usermanual/get-started.html 1.0 Overview When using JMeter you will usuall ...

  5. 51NOD 1432 独木舟(贪心

    1432 独木舟   n个人,已知每个人体重.独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人.显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟? ...

  6. LuoguP3183 [HAOI2016]食物链 记忆化搜索

    题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数.物种的名称为从1到n编号M条能量流动关系形如a1 b1a2 b2a3 b3.... ...

  7. dubbo 实战总结

    1,出现重复调用.因为有重试机制,可以改为异步调用或者幂等操作.

  8. 《C语言程序设计》指针篇<二>

    通过指针引用多维数组 如何理解二维数组元素的地址? 要知道,这本书用了整整两页的内容来讲解这方面的知识,从这里足以看出来理解通过指针来引用二维数组是一件比较麻烦的事情,但是我认为理解并不难. 什么是二 ...

  9. Java中Arrays 与 Collections 的简单操作

    import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.C ...

  10. [原][译][physX]phsyX3.3.4官方文档物理引擎基本概念和例子介绍

    世界和物体: 物理世界包括集合的场景,每个包含的物体称为演员(Actors) 每个场景(Scene)都定义了自己的参考框架包含了所有的时间和空间 在不同的场景,演员不互相影响 演员通常有三种类型:刚体 ...