当说到signal的功能时,我们都知道它会捕捉我们所指定的信号,然后调用我们所指定的信号处理函数。但它是如何捕捉我们指定的信号的呢?下面我就以msdn上关于signal的example为例,说明signal是如何捕捉信号的。

         程序如下:

[cpp] view plain copy

// crt_signal.c  

// compile with: /c  

// Use signal to attach a signal handler to the abort routine  

#include <stdio.h>  

#include <stdlib.h>  

#include <signal.h>  

#include <tchar.h>  

  

void SignalHandler(int signal)  

{  

    printf("Application aborting...\n");  

}  

  

int main()  

{  

    typedef void (*SignalHandlerPointer)(int);  

  

    SignalHandlerPointer previousHandler;  

    previousHandler = signal(SIGABRT, SignalHandler);  

      

    abort();  

}  

        先说一下signal函数的声明:void (*signal(int sig,void (*func)(int)))(int),它的返回值类型是函数指针,这个函数指针指向一个返回值为void类型,接受一个int参数的函数。实际上signal函数返回的是该函数调用前指定信号的处理函数的指针。

        回到程序中来,这个程序很简单,首先定义了一个信号处理函数SignalHandler,然后调用signal用SignalHandler处理所产生的中止信号(SIGABRT)。执行程序时,首先调用signal函数,signal函数的定义(winsig.c中)部分如下:

[cpp] view plain copy

_PHNDLR __cdecl signal(int signum,_PHNDLR sigact)  

{  

    //...  

    switch (signum) {  

            case SIGINT:  

                    //...  

                    break;  

            case SIGBREAK:  

                    //...  

                    break;  

            case SIGABRT:  

            case SIGABRT_COMPAT:  

                    oldsigact = (_PHNDLR) DecodePointer(abort_action);  

                    if(sigact!=SIG_GET)  

                    {  

                        abort_action = (_PHNDLR) EncodePointer(sigact);  

                    }  

                    break;  

            case SIGTERM:  

                    //...  

                    break;  

                }  

     //...  

}  

        我们可以看到,指定了SIGABRT,signal函数就会执行case SIGABRT下面的语句,将指向函数调用前的SIGABRT处理函数的指针赋给oldsigact,将新的处理函数编码后赋给abort_action,这一步非常重要,因为下面的abort()函数就是根据它来得到信号处理函数的。

        接下来执行abort函数,该函数会产生SIGABRT信号,其定义(abort.c中)如下:

[cpp] view plain copy

void __cdecl abort (  

        void  

        )  

{  

    _PHNDLR sigabrt_act = SIG_DFL;  

  

    //...  

  

    sigabrt_act = __get_sigabrt();  

    if (sigabrt_act != SIG_DFL)  

    {  

        raise(SIGABRT);  

    }  

    //...  

    _exit(3);  

}  

         该函数调用__get_sigabrt()取得信号处理函数sigabrt_act,然后调用raise(SIGABRT),在这个函数中调用信号处理函数。raise()的定义()如下:

[cpp] view plain copy

int __cdecl raise (  

        int signum  

        )  

{  

        _PHNDLR sigact;  

        _PHNDLR *psigact;  

        switch (signum) {  

  

                case SIGINT:  

                        sigact = *(psigact = &ctrlc_action);  

                        siglock++;  

                        break;  

  

                case SIGBREAK:  

                        sigact = *(psigact = &ctrlbreak_action);  

                        siglock++;  

                        break;  

  

                case SIGABRT:  

                case SIGABRT_COMPAT:  

                        sigact = *(psigact = &abort_action);  

                        siglock++;  

                        break;  

  

                case SIGTERM:  

                        sigact = *(psigact = &term_action);  

                        siglock++;  

                        break;  

  

                case SIGFPE:  

                case SIGILL:  

                case SIGSEGV:  

                        ptd = _getptd_noexit();  

                        if (!ptd)  

                            return (-1);  

                        sigact = *(psigact = &(siglookup( signum,  

                            ptd->_pxcptacttab )->XcptAction));  

                        goto decode_done;  

                        break;  

  

                default:  

                        /* 

                         * unsupported signal, return an error 

                         */  

                        _VALIDATE_RETURN(("Invalid signal or error", 0), EINVAL, -1);  

        }  

        sigact = (_PHNDLR) DecodePointer(sigact);  

  

decode_done:  

        /* 

         * If the current action is SIG_IGN, just return 

         */  

        if ( sigact == SIG_IGN )  

                return(0);  

  

        /* 

         * If the current action is SIG_DFL, take the default action 

         */  

        if ( sigact == SIG_DFL ) {  

                _exit(3);  

        }  

  

        //...  

                (*sigact)(signum);  

        return(0);  

}  

        在case SIGABRT中将abort_action的值即信号处理函数指针赋给sigact,在最后调用函数(*sigact)(signum)完成对SIGABRT信号的处理。程序对其他信号的捕捉过程也差不多是这样。

        在我这里说的只是一个大概的流程,其中还有很多代码的细节没有涉及到,比如说对预定义的信号处理函数的判断、异常的处理等,这些还有待深入理解和研究。


【VS开发】程序如何捕捉signal函数参数中指定的信号的更多相关文章

  1. Python函数参数中的冒号与箭头

    在一些Python的工程项目中,我们会看到函数参数中会有冒号,有的函数后面会跟着一个箭头,你可能会疑惑,这些都是什么东西? 其实函数参数中的冒号是参数的类型建议符,告诉程序员希望传入的实参的类型.函数 ...

  2. python函数参数中带有默认参数list的坑

    在python中函数参数中如果带有默认参数list遇到问题 先看一段代码 def f(x,l=[]): for i in range(x): l.append(i*i) print(l) print( ...

  3. (转)python中函数参数中如果带有默认参数list的特殊情况

    在python中函数参数中如果带有默认参数list遇到问题 先看一段代码 1 2 3 4 5 6 7 8 9 def f(x,l=[]):     for i in range(x):         ...

  4. 关于cmp函数参数中的&符号

    关于cmp函数参数中的&符号 关于sort函数中的cmp函数有着不同的写法,以刚刚的整形元素比较为例 还有人是这么写的: bool cmp(const int &a, const in ...

  5. 错误“Sources”参数中指定了多次。“Sources”参数不支持重复项。

    在“Sources”参数中指定了项“”多次.“Sources”参数不支持重复项. Asp.Net关于错误“Sources”参数中指定了多次.“Sources”参数不支持重复项. “Sources”参数 ...

  6. PowerShell控制台输出符号+函数参数类型指定+文本内容读取

    There are several ways: Write-Host: Write directly to the console, not included in function/cmdlet o ...

  7. Linux下利用signal函数处理ctrl+c等信号

    前言 linux下能够通过信号机制来实现程序的软中断,是一个很实用的编程方法. 我们平时在程序执行的时候按下ctrl-c.ctrl-z或者kill一个进程的时候事实上都等效于向这个进程发送了一个特定信 ...

  8. Delphi 中 函数参数中的 const 修饰符的本质以及注意事项

    来自:http://blog.csdn.net/farrellcn/article/details/9096787 ------------------------------------------ ...

  9. 通过java程序调用ant build.xml配置文件中指定的target

    一.概述 通过ant实现项目的自动化部署,jar包生成,替换,tomcat关停.启动,查看项目日志: 通过java程序调用已编辑好的ant脚本build.xml配置文件中指定的target: 文中文件 ...

随机推荐

  1. Bzoj 2440: [中山市选2011]完全平方数(莫比乌斯函数+容斥原理+二分答案)

    2440: [中山市选2011]完全平方数 Time Limit: 10 Sec Memory Limit: 128 MB Description 小 X 自幼就很喜欢数.但奇怪的是,他十分讨厌完全平 ...

  2. P1853 投资的最大效益

    题目背景 约翰先生获得了一大笔遗产,他暂时还用不上这一笔钱,他决定进行投资以获得更大的效益.银行工作人员向他提供了多种债券,每一种债券都能在固定的投资后,提供稳定的年利息.当然,每一种债券的投资额是不 ...

  3. AtCoder Grand Contest 039 题解

    传送门 \(A\) 首先只有一串的情况下,遇到相同的肯定是改后面那一个最优,然后两串的话可能要分奇偶讨论一下 //quming #include<bits/stdc++.h> #defin ...

  4. 编译安装和二进制安装mysql

    二进制安装mysql-5.6.46 mysql二进制安装,已经编译成二进制了,只需要做一些配置即可 [root@localhost ~]$ yum install autoconf libaio -y ...

  5. ELK教程2:Kibana的安装

    kibana作为ElastciSearch的数据查询展示界面,集成了很多的功能,本文主要讲述如下部署kibana. 安装 安装命令如下: # 下载kibana的npm wget https://art ...

  6. YII框架的模块化技术

    一.模块的创建 利用yii的自动生成工具gii生成模块. 1.访问:lcoalhost/web/index.php?r=gii 2.点击 Module Generator 下面的 start 3.填写 ...

  7. [Shell]Docker remote api未授权访问漏洞(Port=2375)

    0x01 简介 该未授权访问漏洞是因为docker remote api可以执行docker命令,从官方文档可以看出,该接口是目的是取代docker 命令界面,通过url操作docker. Docke ...

  8. CORS & CSP笔记

    1.CORS & CSP 浏览器跨域相关的安全策略主要存在于两个方面: 浏览器是否发送ajax 浏览器是否加载返回数据 假设从a.com 向b.com发送ajax请求.此时浏览器当前页面为a. ...

  9. DELPHI开发LINUX的动态库

    DELPHI开发LINUX的动态库 WINDOWS的动态库是.dll,这个大家都知道. LINUX也有动态库,扩展名是.so,现在DELPHI也能开发LINUX的动态库哦. DELPHI对LINUX的 ...

  10. 基因表达半衰期 | mRNA Half-Life

    做单细胞RNA-seq分析,自然就能想到我们测到的其实是一个概率学的东西,就像女士品茶里的酵母的泊松分布一样. 真实的细胞里,一切都是连续的,从DNA到mRNA到蛋白,是有一个时间间隔的,每一个pro ...