今天继续对信号进行学习,开始正入正题:

sigaction函数:
安装信号之前我们已经学过一个函数:signal,它最早是在unix上出现的,它是对不可靠信号进行安装的,之后出现了可靠信号和实时信号,所以新的安装函数sigaction函数就出现了,它的原形如下:
 
sigaction结构体:
通过man手册来查看一下它的说明:
 
 
 
关于这些说明,下面会用实验一一来阐述的,所以可以先了解一下既可。
sigaction示例:
下面先来看一下它的简单用法,也就是实现signal相同的功能来安装一个SIGINT信号:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() void handler(int sig); int main(int argc, char *argv[])
{
struct sigaction act;//安装信号时需要传参
act.sa_handler = handler;
sigemptyset(&act.sa_mask);//先将sa_mask清空,关于这个属性的用法之后实验再说明
act.sa_flags = 0;//同样将sa_flags设为0,这个实现不需要关心,之后会说明 if (sigaction(SIGINT, &act, NULL) < )//安装信号
ERR_EXIT("sigaction error\n"); for (;;)
pause();
return ;
} void handler(int sig)
{
printf("recv a sig=%d\n", sig);
}

编译运行:

实际上,对于signal这个安装函数是在可靠的机制之上进行的,也就是说可以认为它是通过sigaction来实现的,所以接下来,用sigaction来模拟signal函数的行为
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() void handler(int sig);
__sighandler_t my_signal(int sig, __sighandler_t handler);//这跟signal的信号安装函数声明一样,实现自己的signal
int main(int argc, char *argv[])
{
/*
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0; if (sigaction(SIGINT, &act, NULL) < 0)
ERR_EXIT("sigaction error\n");
*/
my_signal(SIGINT, handler);
for (;;)
pause();
return ;
} __sighandler_t my_signal(int sig, __sighandler_t handler)
{
struct sigaction act;
struct sigaction oldact;//保存最初的行为
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0; if (sigaction(sig, &act, &oldact) < 0)
return SIG_ERR; return oldact.sa_handler;
} void handler(int sig)
{
printf("recv a sig=%d\n", sig);
}

效果也是一样的,从以上代码可以看出,sigaction功能比signal要强大说了,其中有两个参数需要说明一下:

其中sa_handler只适合不可信号的安装,也就是说不可信号的安装不能用sa_sigaction,这个需要注意。

下面来说明一下sa_mask这个属性是什么效果,然后再回头来看下文字说明:

#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() void handler(int sig); int main(int argc, char *argv[])
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = ; if (sigaction(SIGINT, &act, NULL) < )
ERR_EXIT("sigaction error"); for (;;)
pause();
return ;
} void handler(int sig)
{
printf("recv a sig=%d\n", sig);
sleep();//故意睡眠5秒是为了看在执行期间按了ctrl+\就能立马响应退出信号
}

编译运行:

可以看到,在执行信号处理函数期间,按ctrl+c时,并没有等待sleep5秒完之后,再执行退出动作,而是立马执行了,那能不能改变这种默认,也就是必须得等sleep5秒后再执行退出动作,答案是当然可以的,sa_mask属性就派上用场了:

结果如下:

从实验结果来看,在执行信号处理时,多次按了ctrl+c退出信号,并未立马执行退出动作,而是等执行完了才退出的,这也就是sa_mask的作用,实际上也就是上节学习的信号屏蔽字,不太清楚的可以参考博文:http://www.cnblogs.com/webor2006/p/3751210.html

思考一个问题:sa_mask的作用跟之前学的进程中的信号屏蔽字可以对其信号进行阻塞有什么区别呢?

#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() void handler(int sig); int main(int argc, char *argv[])
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
//sigaddset(&act.sa_mask, SIGQUIT);//将其sa_mask注册去掉,也就是清零了
act.sa_flags = ; sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGINT);
sigprocmask(SIG_BLOCK, &s, NULL);//这就是之前学的,将SIGINT加入到进程的屏蔽字中 if (sigaction(SIGINT, &act, NULL) < )
ERR_EXIT("sigaction error"); for (;;)
pause();
return ;
} void handler(int sig)
{
printf("recv a sig=%d\n", sig);
sleep();
}

编译运行:

这时可以看到,信号被阻塞而压缩就不会执行处理函数了,这也是之前学过时的现象,从实验可以总结出:

sa_mask中指定的掩码也可以阻塞信号,它阻塞的信号是指函数在执行的过程当中,如果发生了在掩码级中指定的信号,信号将被阻塞,直到handler返回,这些信号才能被递达;

sigprocmask它所阻塞的信号表示将这些集合中的信号添加到进程信号屏蔽字当中,这些信号就不能被递达了,既使它发生了。

好了,今天的内容学到这,虽说内容不多,但是还是比较生涩的,下回继续!

linux系统编程之信号(五)的更多相关文章

  1. linux系统编程之信号(七)

    今天继续学习信号,主要是学习关于时间和定时器相关的函数的使用,关于这个实际上有很多内容,这里先简要进行说明,等之后再慢慢进行相关深入,也主要是为接下来要做的一个综合linux系统编程的例子做准备,好了 ...

  2. linux系统编程之信号(二)

    经过了漫长的间歇,对于c语言的学习也被中断了很久,现实确实有很多的无耐,计划中的事情总会被打乱,但不管怎样,学习的道路是不能休止的,所以经过了一断温习后现在继续学习C语言,话不多说,进入正题: 信号分 ...

  3. linux系统编程之信号(一):中断与信号

    一,什么是中断? 1.中断的基本概念 中断是指计算机在执行期间,系统内发生任何非寻常的或非预期的急需处理事件,使得CPU暂时中断当前正在执行的程序而转去执行相应的事件处理程序,待处理完毕后又返回原来被 ...

  4. linux系统编程之进程(五)

    今天继续学习系统编程,学习的主题还是进程,今天主要讨论的是守护进程相关的概念,开始进入正题: 什么是守护进程:       守护进程的创建步骤: 在描述它之前,首先得先了解两个概念:进程组.会话期: ...

  5. linux系统编程之信号(五):信号集操作函数,信号阻塞与未决

    一,信号集及相关操作函数 信号集被定义为一种数据类型: typedef struct { unsigned long sig[_NSIG_WORDS]: } sigset_t 信号集用来描述信号的集合 ...

  6. linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式

        一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统遇到了一个问题: 是重新开始这个系统调用, 还是 ...

  7. linux系统编程之信号(六):信号发送函数sigqueue和信号安装函数sigaction

    一,sigaction() #include <signal.h> int sigaction(int signum,const struct sigaction *act,struct ...

  8. linux系统编程之信号(三):信号安装、signal、kill,arise讲解

    一,信号安装 如果进程要处理某一信号,那么就要在进程中安装该信号.安装信号主要用来确定信号值及进程针对该信号值的动作之间的映射关系,即进程将要处理哪个信号:该信号被传递给进程时,将执行何种操作. li ...

  9. linux系统编程之信号(二):信号处理流程(产生、注册、注销、执行)

        对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个阶段: 信号诞生 信号在进程中注册 信号在进程中的注销 信号处理函数执行 1    信号诞生     信号事件 ...

随机推荐

  1. [LeetCode] 495. Teemo Attacking 提莫攻击

    In LOL world, there is a hero called Teemo and his attacking can make his enemy Ashe be in poisoned ...

  2. 给通过canvas生成的二维码添加logo

    以jquery.qrcode为例来说, 生成二维码代码: 依赖jquery.js, jquery.qrcode.js //计算宽,高,中心坐标,logo大小 var width = 256,heigh ...

  3. [转] ABP框架Web API跨域问题的解决方案

    原文地址:​https://www.cnblogs.com/farb/p/ABPWebAPICrossDomain.html 1.在Web Api 项目下安装 Microsoft.AspNet.Web ...

  4. QT--学习疑惑探索

    用C++定义了一个类,并注册到qml文件中,但是这个类只能用Quickview进行显示,用其他方法好像不行. 启发: 1  window控件类是没有parent的widget. 2 m_view = ...

  5. 【Linux】僵尸进程,孤儿进程以及wait函数,waitpid函数(有样例,分析很详细)

    本文内容: 1.僵尸进程,孤儿进程的定义,区别,产生原因,处理方法 2.wait函数,waitpid函数的分析,以及比较 背景:由于子进程的结束和父进程的运行是一个异步的过程,即父进程永远无法预测子进 ...

  6. js玩命加载……

    在请求数据加载的过程中,经常需要显示请求等待,写了一个简单的请求等待—- html代码如下 <!--页面载入显示--> <div id="dataLoad" st ...

  7. 用海豚框架(DolphinPHP)实现单/多图片上传时,如何获得图片路径

    用框架实现图片上传很简单,就不多说了,然后这个框架的实现机制是这样的,我们选择图片,点击上传,他会将图片保存在uploads下,以当天时间和随机字母作为图片名,然后在返回个数字,这个数字是这个图片的i ...

  8. PB数据窗口只存储过程数据源创建

    必须在 Manual Rault Set 上打勾,不然不能设置显示列. 显示列的数据必须和存储过程返回值的顺序一致,否则会出现数据和列名两边不对应的情况

  9. idea 中激活 JRebel

    JRebel介绍: JRebel是一款JVM插件,它使得Java代码修改后不用重启系统,立即生效.IDEA上原生是不支持热部署的,一般更新了 Java 文件后要手动重启 Tomcat 服务器,修改才能 ...

  10. 【洛谷 P3193】 [HNOI2008]GT考试(KMP,dp,矩阵乘法)

    题目链接 \(f[i][j]\)表示准考证号到第\(i\)位,不吉利数字匹配到第\(j\)位的方案数. 答案显然是\(\sum_{i=0}^{m-1}f[n][i]\) \(f[i][j]=\sum_ ...