今天继续探讨信号相关的东东,话不多说,正入正题:

信号在内核中的表示:
下面用图来进一步描述这种信号从产生到递达之间的状态(信号阻塞与未诀):
 
那是怎么来决定的呢?下面慢慢来举例分解:
所以,通过这些图,可以描述信号从产生到递达的一个过程,上面的理解起来可能有点难,下面会用代码来进一步阐述,在进行实验之前,还需了解一些函数的使用,这些函数在实验中都会被用到,也就是信号集操作函数。
信号集操作函数:
其中解释一下sigset_t,百度百科解释为:
而这个函数的意义就是将这64位清0
这个函数的意义是将这屏蔽字的64位都变为1
将这个信号所对应的位置为1
将这个信号所对应的位置为0
检测这一个信号所对应的位当前是0还是1
 
以上是操作信号集的五个相关的函数,但是注意:这五个函数仅仅是改变这个信号集变量,如set,并非真正改变进程信号当中的屏蔽字,所以接下来介绍的函数就是改变信号当中的屏蔽字的
sigprocmask:
好了,理论说了很多,下面正式开始实验,来体会一下一个信号从产生到递达的一个状态转换过程:
首先,我们打印出系统的未诀信号,目的是为了观察之后的状态:
#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);
void printsigset(sigset_t *set)//打印出信号集的状态,其中参数set为未诀状态的信号集
{
int i;
for (i=1; i<NSIG; ++i)//NSIG表示信号的最大值,也就是等于64
{
if (sigismember(set, i))//说明是未诀状态的信号
putchar('1');
else
putchar('0');//说明不是未诀状态的信号
}
printf("\n");
} int main(int argc, char *argv[])
{
sigset_t pset; for (;;)
{
sigpending(&pset);//该函数是获取进程当中未诀状态的信号集 ,保存在pset当中
printsigset(&pset);//打印信号集的状态,看有没有未诀状态的信号产生
sleep();
}
return ;
}

【说明】:sigpending是用来获取进程中所有的未诀信号集:

这时看一下运行效果:

可以发现,当前状态没有未诀的信号,因为还没有被阻塞的信号过,信号也没有产生过,所以不可能有未诀的状态。
这时,我们来安装一个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);
void printsigset(sigset_t *set)
{
int i;
for (i=; i<NSIG; ++i)
{
if (sigismember(set, i))
putchar('');
else
putchar('');
}
printf("\n");
} int main(int argc, char *argv[])
{
sigset_t pset;
if (signal(SIGINT, handler) == SIG_ERR)//安装一个SIGINT信号
ERR_EXIT("signal error"); for (;;)
{
sigpending(&pset);
printsigset(&pset);
sleep();
}
return ;
} void handler(int sig)
{
printf("recv a sig=%d\n", sig);
}

这时再看下效果:

从结果来看,信号被直接递达了,所以这次也没有看到有1的未诀状态的信号,因为信号必须被阻塞才会出现未诀状态,所以接下来将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);
void printsigset(sigset_t *set)
{
int i;
for (i=; i<NSIG; ++i)
{
if (sigismember(set, i))
putchar('');
else
putchar('');
}
printf("\n");
} int main(int argc, char *argv[])
{
sigset_t pset; sigset_t bset;
sigemptyset(&bset);//将信号集清0
sigaddset(&bset, SIGINT);//将SIGINT所对应的位置1 if (signal(SIGINT, handler) == SIG_ERR)
ERR_EXIT("signal error"); sigprocmask(SIG_BLOCK, &bset, NULL);//更改进程中的信号屏蔽字,其中第三个参数传NULL,因为不关心它原来的信号屏蔽字
for (;;)
{
sigpending(&pset);
printsigset(&pset);
sleep();
}
return ;
} void handler(int sig)
{
printf("recv a sig=%d\n", sig);
}

编译运行:

从结果来看,将SIGINT信号来了,由于添加到了信号屏蔽字为1,所以会被阻塞掉,并且可以看到SIGINT对应的位也打印为1了。

【说明】:SIGINT对应的位是指:

下面,我们做一件事情,就是当我们按下ctrl+\解除阻塞,这样处于未诀状态的信号就会被递达,则对应的未诀状态位也会还原成0,具体代码如下:

#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);
void printsigset(sigset_t *set)
{
int i;
for (i=; i<NSIG; ++i)
{
if (sigismember(set, i))
putchar('');
else
putchar('');
}
printf("\n");
} int main(int argc, char *argv[])
{
sigset_t pset;
sigset_t bset;
sigemptyset(&bset);
sigaddset(&bset, SIGINT);
if (signal(SIGINT, handler) == SIG_ERR)
ERR_EXIT("signal error");
if (signal(SIGQUIT, handler) == SIG_ERR)//注册一个ctrl+c信号
ERR_EXIT("signal error"); sigprocmask(SIG_BLOCK, &bset, NULL);
for (;;)
{
sigpending(&pset);
printsigset(&pset);
sleep();
}
return ;
} void handler(int sig)
{
if (sig == SIGINT)
printf("recv a sig=%d\n", sig);
else if (sig == SIGQUIT)
{
sigset_t uset;//当按下ctrl+\时,则对SIGINT信号解除阻塞
sigemptyset(&uset);
sigaddset(&uset, SIGINT);
sigprocmask(SIG_UNBLOCK, &uset, NULL);
}
}

编译运行:

从中可以看到,当我们按下ctrl+\时,并没有退出,而是解除了阻塞,所以对应的SIGINT位也变为0了。

另外,看下这种情况:

多次按了ctrl+c,可在按ctrl+\解除阻塞时,只响应了一次信号处理函数,这也由于SIGINT是不可靠信号,不支持排队。

另外,由于我们捕获了ctrl+\信号,所以没办法退出这个进程了,那怎么办呢,可以利用shell命令将其强制杀掉如下:

好了,今天学的东西可能有些生涩,需好好消化,下节再见!

 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction

    信号发送函数sigqueue和信号安装函数sigaction sigaction函数用于改变进程接收到特定信号后的行为. sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然 ...

随机推荐

  1. [LeetCode] 409. Longest Palindrome 最长回文

    Given a string which consists of lowercase or uppercase letters, find the length of the longest pali ...

  2. Anaconda无法更新

    在安装完Anaconda,更新包时 C:\Users\Administrator>conda upgrade --all WARNING: The conda.compat module is ...

  3. 修改jar的.class文件,并重新打包

    使用javassist修改.class文件,并重新打包 Javassist是一款字节码编辑工具,可以直接编辑和生成Java生成的字节码,以达到对.class文件进行动态修改的效果.熟练使用这套工具,可 ...

  4. 【神经网络与深度学习】Win10+VS2015 caffe环境搭建(极其详细)

    caffe是好用,可是配置其环境实在是太痛苦了,依赖的库很多不说,在VS上编译还各种报错,你能想象那种被一百多个红色提示所笼罩的恐惧.  且网上很多教程是VS2013环境下编译的,问人很多也说让我把1 ...

  5. spring security的BCryptPasswordEncoder加密和对密码验证的原理

    目录 BCryptPasswordEncoder加密和对密码验证的原理 一.加密算法和hash算法的区别 二.源码解析 1. encode方法 2. BCrypt.hashpw方法 3. matche ...

  6. mysql 的日期和时间函数

    执行函数方式 select 函数  函数名称 函   数 功   能 CURDATE() 获取当前日期 CURTIME() 获取当前时间 NOW() 获取当前的日期和时间 UNIX_TIMESTAMP ...

  7. SpringBoot(1)

    SpringBoot 8/2 CRUD 发送put请求修改数据有三个步骤: SpringMVC中配置HiddenHttpMethodFilter 页面上创建一个post请求(form标签只能写get和 ...

  8. Python 爬取陈都灵百度图片

    Python 爬取陈都灵百度图片 标签(空格分隔): 随笔 今天意外发现了自己以前写的一篇爬虫脚本,爬取的是我的女神陈都灵,尝试运行了一下发现居然还能用.故把脚本贴出来分享一下. import req ...

  9. python技巧 — 整合 User-Agent 大全汇总

    一.IE 浏览器 而IE各个版本典型的userAgent如下:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)Mozilla/4.0 (compat ...

  10. 【Linux】一步一步学Linux——Centos7.5安装图解(08)

    00. 目录 参考博客:https://mp.csdn.net/mdeditor/95031775# 01. Centos7.5简介 CentOS(Community Enterprise Opera ...