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

信号在内核中的表示:
下面用图来进一步描述这种信号从产生到递达之间的状态(信号阻塞与未诀):
 
那是怎么来决定的呢?下面慢慢来举例分解:
所以,通过这些图,可以描述信号从产生到递达的一个过程,上面的理解起来可能有点难,下面会用代码来进一步阐述,在进行实验之前,还需了解一些函数的使用,这些函数在实验中都会被用到,也就是信号集操作函数。
信号集操作函数:
其中解释一下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] 295. Find Median from Data Stream 找出数据流的中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  2. 【网络开发】详谈socket请求Web服务器过程

    最开始我们需要明白一件事情,因为这是这篇文章的前提: HTTP协议只是一个应用层协议,它底层是通过TCP进行传输数据的.因此,浏览器访问Web服务器的过程必须先有"连接建立"的发生 ...

  3. git pull时 git cannot lock ref XXXXXX (unable to update local ref)错误解决方案

    git pull :  git cannot lock ref    XXXXXX (unable to update local ref) pull代码的时候出现的错误,导致代码拉不下来. 看了一下 ...

  4. idea设置内存大小

    1.打开idea安装路径下bin,编辑.vmoptions两个文件 然后重启一下idea 2.直接打开idea的.vmoptions文件进行编辑

  5. 2019年广东外语外贸大学程序设计竞赛(新手赛)-F题(好快的刀)题解

    题面: 题目意为,任意连接两个圆的圆心形成一条直线,计算与该直线相交或相切的圆的数量,求这些直线最多能相交或相切多少个圆 解题思路: 遍历所有的圆,计算出两圆圆心生成的直线,再遍历其他的圆,检测这些圆 ...

  6. linux命令及相关配置

    hostname # 查看 hostname vim /etc/hostname # 修改hostname,重启后生效 vim /etc/resolv.conf 写入 nameserver 192.1 ...

  7. [十一集训] Day1 (2018-2019 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2018))

    A Altruistic Amphibians 原题 题目大意: n只青蛙在高度为d的井中,每只有跳跃距离.重量和高度,每只青蛙可以借助跳到别的青蛙的背上而跳出井,每只青蛙能承受的最大重量是自身重量, ...

  8. 2.Netty 与 NIO 之前世今生

      2.Netty 与 NIO 之前世今生 本文围绕一下几点阐述: 1. NIO 的核心组件 Buffer.Selector.Channel. 2.何谓多路复用? 3.Netty 支持的功能与特性. ...

  9. Find the median(线段树+离散化)(2019牛客暑期多校训练营(第七场))

    题目出处:Find the median 示例: 输入: 53 1 4 1 5 92 7 1 8 2 9 输出:3 4 5 4 5 说明:L = [3, 2 ,4, 1, 7],R = [4, 8, ...

  10. ColorMatrixFilter色彩矩阵滤镜

    ColorMatrixFilter色彩矩阵滤镜: /** * * *----------------------------------------* * | *** ColorMatrixFilte ...