今天继续对信号进行研究,话不多说,言归正传:

更多信号发送函数:
上节中我们已经接触到了一些信号的发送函数,这里更进一步学习一下其它的发送函数:
alarm:只能发送SIGALRM信号
下面通过一个例子来介绍这个函数:
#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[])
{
if (signal(SIGALRM, handler) == SIG_ERR)//注册了一个alrm信号
ERR_EXIT("signal error"); alarm();//发送一个alarm信号
for (;;)
pause();
return ;
} void handler(int sig)
{
printf("recv a sig=%d\n", sig);
}

关于alarm函数的说明可以查看man:

运行效果:

可见,是隔了一秒才发送出alarm信号的,实际上,我们可以找到该进程,用shell命令中人为的发送该信号:

通过kill命令来发送信号,为了看到效果,新开一个命令终端,效果如下:

可以看到手动发送信号也是可以正常收到的,另外,我们在发送信号时,既可以用数字,也可以用它对应的名称,如下:

实际上,对于进程的ID,可以通过动态方式来获取,按如下步骤(了解一下)

1、先过滤掉其它行

2、然后再只得到进程ID列,过滤掉其它列

所以,手动发送信号时,就可以用动态的方式来发送了,如下:
说明:关于这个语法,在基础linux上会记录到,先了解下这种用法。
我们发现,alarm函数不能每隔一秒发送一次信号,那如果要做到这点该怎么办呢?
效果如下:
 
 
 
setitimer:发送SIGALRM、SIGVTALRM、SIGPROF信号
 
abort:只能发送SIGABRT信号
 
可重入函数与不可重入函数:
关于什么是可重入函数和不可重入函数, 这个比较难以理解,下面先阐述下概念,然后再通过实验来进一步理解:
太抽象了,下面用实验来说明:
#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() typedef struct
{
int a;
int b;
} TEST; TEST g_data;//定义了一个全局变量,是为了说明不可重入函数的问题 void handler(int sig);
int main(int argc, char *argv[])
{
TEST zeros = {, };
TEST ones = {, };
if (signal(SIGALRM, handler) == SIG_ERR)
ERR_EXIT("signal error"); g_data = zeros;//默认赋值
alarm();
for (;;)
{
g_data = zeros;
g_data = ones;//不断对其进行赋值,正常情况应该要不是zeros,要不就是ones
}
return ;
} void handler(int sig)
{
printf("%d %d\n", g_data.a, g_data.b);//打印出值,观察其输出可以看到不可重录函数的缺点
alarm();
}

编译运行:

这是为什么呢?

这是由于有一个全局变量g_data,而且在for循环中不断进行赋值,

由于赋值不是一个原子操作,拿g_data=zeros这个赋值操作来说,由两部组成:

①g_data.a = zeros.a;

②g_data.b = zeros.b

如果g_data之前的值为ones,当执行到第①步赋值操作时,信号来了终止了第②步赋值操作,那处理handler打印时,则会打印出0,1,因为第二个赋值操作停止了,造成了只赋值了一部分,所以上面程序的打印结果就可以解释了,将handler中的打印语句提取到一个新的函数中:
导致不可重录函数的原因,是由于:
中断之前的处理程序跟中断程序访问了一些共享数据g_data,
【说明】:如果此处不访问g_data的话,也就不会产生不可重录的问题。
所以导致不可重录只要有以下几个方面:
那一些函数才算是安全可以在信号处理函数中使用呢?查看man帮助:
除了这些函数是安全的之外,其它的都是不安全的,所以说使用信号是很容易出错的,现在的内核也正在考虑有没有一个机制来替换信号,实际上正在考虑能否用文件描述符来替换信号,这正是下个内核要实现的功能,将信号融入到文件描述上进行处理。
 

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

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

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

  2. linux系统编程之管道(三)

    今天继续研究管道的内容,这次主要是研究一下命名管道,以及与之前学过的匿名管道的区别,话不多说,进入正题: 所以说,我们要知道命名管道的作用,可以进行毫无关系的两个进程间进行通讯,这是匿名管道所无法实现 ...

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

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

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

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

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

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

  6. linux系统编程之信号(八):三种时间结构及定时器setitimer()详解

    一,三种时间结构 time_t://seconds   struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microsecond ...

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

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

  8. linux系统编程之信号(一)

    今天起,开始新的知识的学习,对于上个系列进程的学习还差一个理论上的总结,这个会下次补回来,以便通过实践之后,再用理论将其巩固一下,好了,话不多说,开始进入这个主题的学习----信号,很重要,但不是太容 ...

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

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

随机推荐

  1. 转载:Python Web开发最难懂的WSGI协议,到底包含哪些内容?

    原文:PSC推出的第二篇文章-<Python Web开发最难懂的WSGI协议,到底包含哪些内容?>-2017.9.27 我想大部分Python开发者最先接触到的方向是WEB方向(因为总是有 ...

  2. POJ 1014 Dividing(入门例题一)

    Time Limit: 1000MS Memory Limit: 10000K Total Submissions: Accepted: Description Marsha and Bill own ...

  3. POJ 1458 Common Subsequence(最长公共子序列)

    题目链接Time Limit: 1000MS Memory Limit: 10000K Total Submissions: Accepted: Description A subsequence o ...

  4. Python2.7+virtualenv+CUDA 10.0版的pytorch v1.3.0 +运行人群计数crowdcount-mcnn网络

    Python2.7$ python2 -m virtualenv pytorchenv$ source pytorchenv/bin/activate $ pip install ipython py ...

  5. tensorboard 拒绝访问解决方法

    打开Anaconda Prompt,切换到TensorFlow环境(activate tensorflow) 切换成功之后,输入tensorboard --logdir='路径' 注意:--logdi ...

  6. jQuery无缝轮播图思路详解-唯品会

    效果图如上: 需求:图片自动轮播,鼠标移上停止播放,离开恢复播放,箭头切换图片. html代码 <!--轮播图大盒子开始--> <div class="wrap" ...

  7. ArcGIS JS 使用Proxy之 Printing Tools unable to connect to mapServer

    ArcGIS JS使用Proxy.ashx将地图服务隐藏,并在微博服务器端增加了地图服务权限判断. Proxy.ashx做了如下设置, <serverUrl url="http://l ...

  8. Postman 基本使用

    Postman 基本使用   Postman主界面 工具栏 New: 新建,可以新建Request请求,Collection请求集,环境等等 Import: 导入,可以导入别人导出的请求集 Runne ...

  9. Delphi调用爷爷类的方法(自己构建一个procedure of Object)

    Delphi通过inherited 可以调用父类的方法,但是没有提供直接调用父类的父类的方法(爷爷类),通过变通的方式实现如下: 假设父类是TFather,爷爷类TGrand,调用爷爷类的Write方 ...

  10. AGC028E High Elements 贪心、DP、线段树

    传送门 看到要求"字典序最小"的方案,一个很直观的想法是按位贪心,那么我们需要check的就是当某一个数放在了第一个序列之后是否还存在方案. 假设当前两个序列的最大值和前缀最值数量 ...