信号学习一

信号的基本概念

硬件中的 “中断” 是为了立即响应,而 “信号” 是中断的软件实现。在程序中不需要通过通过 “轮询” 的方式来判断是否有事件发生,只要进程收到信号就会立即响应。“信号” 的发生完全是不可预测的,但是一旦信号发生了,却会有相应的处理程序。比如当程序卡死,在键盘上按下组合键 Cltr + C ,向该程序发送 SIGINT 信号,程序就会终止。“信号” 的特点使得它很容易来实现 “异步消息响应机制”, 这使得我们程序处理更加灵活。UNIX中有很多产生信号的方式,比如cltr+c组合键产生中断信号,又或者使用 kill 命令向进程发送任意信号。信号的产生最终是为了作出快速响应。内核对信号的处理方法就是以下的三种:

  1. 忽略信号:内核对信号不作出任何响应,忽略该信号。但是SIGKILL, SIGSTOP 是不能忽略的,原因在于它们向内核和超级用户提供了使进程终止或者停止的可靠方法。
  2. 捕捉信号:内核可以通过用户设置好的捕捉函数来作出相应的处理。下面会说到如何设置捕捉函数。
  3. 默认动作:对所有的信号内核都有一个默认动作,如果用户未设置捕捉函数,那么这是内核的默认动作。大部分的默认动作为终止进程。

常见信号

不同的unix平台下支持的信号种类各不相同,可以使用 kill -l 来查看。这里只列举出几个常见的,重要的信号来进行说明还有解释。见下表:

名字 说明 默认动作
SIGABRT 异常终止(abort) 终止+core
SIGALRM 定时器超时(alram) 终止
SIGINT 终端中断符 终止
SIGKILL 终止 终止
SIGQUIT 终端退出符 终止+core
SIGSEGV 无效内存引用 终止+core
SIGUSR1 用户定义信号 终止

signal函数

如果用户想对某个信号定义自己的处理函数,那么就需要用到这个 signal 接口函数进行信号捕捉函数的注册了。下面是这个函数的定义:

#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
                                返回值:若成功,返回以前的信号处理配置;若出错,返回SIG_ERR

这个复杂的函数声明我还是第一次见到,在没有理解之前着实让我费解。这里先讲这个函数怎么用,然后再解释这个函数声明。

signal 函数需要传入两个参数,signo为我们程序想要捕捉的信号名。比如 SIGINT。第二个参数是一个函数地址。该函数需要传入一个int型,无返回值。unix系统也我们提供了三个处理函数,

  • SIG_ERR 表示signal函数出错
  • SIG_DEL 表示对信号采用默认动作
  • SIG_IGN 表示忽略该信号

signal 函数的一般编程写法如下:

static void sig_usr1(int);

if ((signal(SIG_USR1, sig_usr1)) == SIG_ERR)
{
    /* error handler code */
    ...
}
...

static void sig_usr1(int signo)
{
    /* the signal SIGUSR1 handler code*/
    ...
}

现在知道了 signal 函数该怎么用了,再后头看看这个函数的声明。直接看上面这个复杂的声明确实很难看懂,书上将其转换成下面这个形似:

typedef void Sigfunc(int);
Sigfunc *signal(int, Sigfunc*)

说实话我只能看懂 signal 函数的参数,一个是 int, 一个是函数地址。我总是在纠结函数声明中最后的一个 int ,实在看不懂它的作用是什么。后来我把 Sigfunc先替换成我们常见的类型,比如: int *signal(int, Sigfunc*); 一下子就豁然开朗了。就是个返回值嘛! signal 函数奇怪就奇怪在它的返回值,它返回的是一个函数指针,这个函数指针对应的函数形参为一个 int 型,无返回值。这一下就理解了这个 signal 函数了。

下面是一个 signal 函数的实例,抄自书上,并无太多新意:

# include "apue.h"

static void sig_usr(int);

int main(void)
{
    if (signal(SIGUSR1, sig_usr) == SIG_ERR)
        err_sys("can‘t catch SIGUSR1");
    if (signal(SIGUSR2, sig_usr) == SIG_ERR)
        err_sys("can‘t catch SIGUSR2);

    for ( ; ; )
        pause();
}

static void sig_usr(int signo)
{
    if (signo == SIGUSR1)
        printf("received SIGUSR1\n");
    else if (signo == SIGUSR2)
        printf("received SIGUSR2\n");
    else
        err_sdump("received signal %d\n", signo);
}

这里再补充说明一下 signal 函数的返回值。即 "以前信号的处理配置" 的含义。当调用 signal 函数注册信号处理函数,如果成功,则返回此信号的上一个注册的信号处理函数的地址。要理解这一点,可以看看下面的这段测试代码:

#include "apue.h"
static void sig_usr(int);
static void sig_usr2(int);

int main(void)
{
    Sigfunc *pfunc;
    pfunc = signal(SIGUSR1, sig_usr);
    printf("the pfunc addr is %p\n", pfunc); /* 打印0,因为SIGUSR1信号并未注册*/

    pfunc = signal(SIGUSR1, sig_usr2);
    if (pfunc == SIG_ERR)
        printf("can not use sig_usr2 to handle SIGUSR1\n");

    // print the sig_usr addr
    printf("the sig_usr addr is %p\n", sig_usr);
    printf("the pfunc addr is %p\n", pfunc);         /* 两者的地址一样 */
    while (1)
        pause();
}
时间: 2024-10-21 06:25:32

信号学习一的相关文章

Python模块之信号学习(signal)

信号概述 在学习Python前应该学习下Linux下的信号,软中断信号(signal,又简称为信号)用来通知进程发生了异步事件.进程之间可以互相通过系统调用kill发送软中断信号.内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件.注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据. 信号种类 Linux中的信号种类(从图中可以看到没有32.33这俩个信号) 普通信号:1-----31号信号 实时信号:34---64号信号 通过指令      kill  信号序号

信号学习第一课--基础知识

信号是某些错误条件而引起由shell和终端管理器生成的signal可以作为进程间传递消息或者修改行为的一种方式,明确的由一个进程传递给另外一个进程信号可以被生成,捕获,响应,或者忽略. 程序可以使用signal库函数来处理信号 1 #include <signal.h> 2 void (* signal (int sig, void (* func) (int))) (int); signal是一个带有sig和func两个参数的函数 准备捕获或者忽略的信号由参数sig给出 接收到指定的信号后将

看DeepMind如何用Reinforcement learning玩游戏

原文地址:http://www.infoq.com/cn/articles/atari-reinforcement-learning 原文作者:作者简介 尹绪森,Intel实习生,熟悉并热爱机器学习相关内容,对自然语言处理.推荐系统等有所涉猎.目前致力于机器学习算法并行.凸优化层面的算法优化问题,以及大数据平台性能调优.对Spark.Mahout.GraphLab等开源项目有所尝试和理解,并希望从优化层向下,系统层向上对并行算法及平台做出贡献. 引子 说到机器学习最酷的分支,非Deep lear

转--脉络清晰的BP神经网络讲解,赞

http://www.cnblogs.com/wengzilin/archive/2013/04/24/3041019.html 学 习是神经网络一种最重要也最令人注目的特点.在神经网络的发展进程中,学习算法的研究有着十分重要的地位.目前,人们所提出的神经网络模型都是和学习算 法相应的.所以,有时人们并不去祈求对模型和算法进行严格的定义或区分.有的模型可以有多种算法.而有的算法可能可用于多种模型.不过,有时人们也称算法 为模型. 自从40年代Hebb提出的学习规则以来,人们相继提出了各种各样的学

SDCC2013大会笔记整理

2013-8-30 大会首日 百度移动云三大框架:Clouda.SiteApp.Appbuilder MBaaS解决高性能Server很难构建的问题. 百度开放云的区域运营服务于创业者 --------------------------------- pinterest的架构变迁: 互联网就是把线下的一些东西搬到线上. 首创瀑布流 网站流量经历过一个长的沉寂期 核心用户进入创业团队 流量爆发时会产生很大压力 经验:1.保持简单:2.大用户碰到的问题大于普通用户:3.新技术看上去很美 使技术体系

脉络清晰的BP神经网络讲解,赞

学习是神经网络一种最重要也最令人注目的特点.在神经网络的发展进程中,学习算法的研究有着十分重要的地位.目前,人们所提出的神经网络模型都是和学习算 法相应的.所以,有时人们并不去祈求对模型和算法进行严格的定义或区分.有的模型可以有多种算法.而有的算法可能可用于多种模型.不过,有时人们也称算法 为模型. 自从40年代Hebb提出的学习规则以来,人们相继提出了各种各样的学习算法.其中以在1986年Rumelhart等提出的误差反向传播法,即BP(error BackPropagation)法影响最为广

【转】BP神经网络

学习是神经网络一种最重要也最令人注目的特点.在神经网络的发展进程中,学习算法的研究有着十分重要的地位.目前,人们所提出的神经网络模型都是和学习算 法相应的.所以,有时人们并不去祈求对模型和算法进行严格的定义或区分.有的模型可以有多种算法.而有的算法可能可用于多种模型.不过,有时人们也称算法 为模型. 自从40年代Hebb提出的学习规则以来,人们相继提出了各种各样的学习算法.其中以在1986年Rumelhart等提出的误差反向传播法,即BP(error BackPropagation)法影响最为广

云计算vs雾计算:物联网的发展能否「云开雾散」?

物联网就是一场数据的战争,怎么能够从庞大的数据海中挖掘出有价值的信息对于物联网的发展的胜利,众所周知未来将是一个万物互联的时代,随着物联网行业技术标准的完善以及关键技术上的不断突破,数据大爆炸时代将越走越近,对计算的要求也越来越高. 说云计算小伙伴们可能都知道,但雾计算就给懵了.相比于云计算的高高在上和遥不可及,雾计算更为贴近地面,就在你我身边. 太复杂的概念小编就不提了,随便百度一下就能出来无数种介绍. 小编给大家简单介绍一下几个关键点. 什么是雾计算? 现在大多数人认为的"雾计算"

APUE学习笔记——10.9 信号发送函数kill、 raise、alarm、pause

转载注明出处:Windeal学习笔记 kil和raise kill()用来向进程或进程组发送信号 raise()用来向自身进程发送信号. #include <signal.h> int kill(pid_t pid,int signo); int raise(int signo); Both return: 0 if OK,?1 on error kill向进程号为pid的进程发送signo信号 能够看出 以下两行代码是等价的: kill(getpid(), signo); raise(sig